@chakra-ui/react#Tr JavaScript Examples
The following examples show how to use
@chakra-ui/react#Tr.
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: Table.js From web-client with Apache License 2.0 | 6 votes |
CommandsTable = ({ commands, onDeleteCallback = null }) => {
return <Table>
<Thead>
<Tr>
<Th style={{ width: '190px' }}>Name</Th>
<Th className='only-desktop'>Description</Th>
<Th>Execution environment</Th>
<Th>Output parser</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{null === commands && <LoadingTableRow numColumns={5} />}
{null !== commands && 0 === commands.length && <NoResultsTableRow numColumns={5} />}
{null !== commands && 0 !== commands.length && commands.map(command =>
<Tr key={command.id}>
<Td><CommandBadge command={command} /></Td>
<Td className="only-desktop">
{command.description}<br />
<Tags values={command.tags} />
</Td>
<Td>{command.executable_type === 'custom' ? 'Host' : 'Container'}</Td>
<Td>{command.output_parser ?? '-'}</Td>
<Td textAlign="right">
<LinkButton href={`/commands/${command.id}/edit`}>Edit</LinkButton>
{onDeleteCallback && <DeleteIconButton onClick={() => onDeleteCallback(command.id)} />}
</Td>
</Tr>
)}
</Tbody>
</Table>
}
Example #2
Source File: BuilderListSkeleton.jsx From scaffold-directory with MIT License | 6 votes |
BuilderListSkeleton = () => (
<Box overflowX="auto">
<Center mb={5}>
<chakra.strong mr={2}>Total builders:</chakra.strong> <SkeletonText noOfLines={1} w={5} />
</Center>
<Table>
<Thead>
<Tr>
<Th>Builder</Th>
<Th>Challenges</Th>
<Th>Socials</Th>
<Th>Last Activity</Th>
</Tr>
</Thead>
<Tbody>
{[1, 2].map(lineNumber => {
return (
<Tr key={lineNumber}>
<Td>
<SkeletonAddress w="12.5" fontSize="16" />
</Td>
<Td>
<SkeletonText noOfLines={1} py={2} />
</Td>
<Td>
<SkeletonText noOfLines={1} py={2} />
</Td>
<Td>
<SkeletonText noOfLines={1} py={2} />
</Td>
</Tr>
);
})}
</Tbody>
</Table>
</Box>
)
Example #3
Source File: RecentActivityWidget.js From web-client with Apache License 2.0 | 6 votes |
RecentActivityWidget = () => {
const [auditLog] = useFetch('/auditlog?limit=5');
return <DashboardWidget title="Recent activity">
{auditLog && auditLog.length > 0 ?
<Table>
<Thead>
<Tr>
<Th>Action</Th>
<Th>User</Th>
<Th>Date/Time</Th>
</Tr>
</Thead>
<Tbody>
{auditLog.map(log => <Tr key={log.id}>
<Td><Badge>{log.action}</Badge></Td>
<Td>{log.user_name ?
<UserLink userId={log.user_id}>{log.user_name}</UserLink> : '-'}</Td>
<Td>{log.insert_ts}</Td>
</Tr>)}
</Tbody>
</Table> :
<p>No activity to show.</p>
}
</DashboardWidget>
}
Example #4
Source File: components.js From idena-web with MIT License | 6 votes |
export function FlipsHiddenDescRow({children}) {
return (
<Tr display={['table-row', 'none']}>
<Td colSpan={3} px={0} pt={1} pb={3}>
<Box bg="gray.50" borderRadius="md" px={5} py={2}>
{children}
</Box>
</Td>
</Tr>
)
}
Example #5
Source File: Table.js From web-client with Apache License 2.0 | 6 votes |
NotesTable = ({ notes, onDeleteButtonClick }) => {
return <Table>
<Thead>
<Tr>
<Th>Content</Th>
<Th style={{ width: '200px' }}>Creation time</Th>
<Th style={{ width: '140px' }}>Author</Th>
<Th style={{ width: '140px' }}>Visibility</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{notes.length === 0 && <NoResultsTableRow numColumns={5} />}
{notes.map((note, index) =>
<Tr>
<Td><ReactMarkdown>{note.content}</ReactMarkdown></Td>
<Td><ReactTimeAgo date={note.insert_ts} /></Td>
<Td><UserLink userId={note.user_id}>{note.user_name}</UserLink></Td>
<Td><VisibilityLegend visibility={note.visibility} /></Td>
<Td>
<RestrictedComponent roles={['administrator', 'superuser', 'user']}>
<DeleteIconButton onClick={ev => onDeleteButtonClick(ev, note)} />
</RestrictedComponent>
</Td>
</Tr>
)}
</Tbody>
</Table>
}
Example #6
Source File: TechStack.js From benjamincarlson.io with MIT License | 5 votes |
TechStack = () => {
const { colorMode } = useColorMode()
const colorSecondary = {
light: 'gray.600',
dark: 'gray.400'
}
const linkColor = {
light: 'blue.400',
dark: 'blue.600'
}
return (
<Box as="section" w="100%" mt={10} mb={20}>
<Heading letterSpacing="tight" size="lg" fontWeight={700} as="h2" mb={4}>
Tech Stack ⚙️
</Heading>
<Text color={colorSecondary[colorMode]} mb={4}>Each piece of technology used in this website is carefully thought out. I believe this is one of the best stacks there is to build websites of any size and domain.</Text>
<Box flexDir="column" overflowX="auto">
<Table variant="simple">
<Thead>
<Tr>
<Th>Type</Th>
<Th>Name</Th>
<Th>Route</Th>
<Th>Description</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td>JS Framework</Td>
<Td><Link href="https://nextjs.org" color={linkColor[colorMode]} isExternal>Next JS</Link></Td>
<Td>n/a</Td>
<Td>Next.js was an easy choice given its large community and ability for rapid development.</Td>
</Tr>
<Tr>
<Td>CSS Framework</Td>
<Td><Link href="https://chakra-ui.com" color={linkColor[colorMode]} isExternal>Chakra UI</Link></Td>
<Td>n/a</Td>
<Td>I use Chakra UI because its components make a beautiful UI out of the box and are highly customizable.</Td>
</Tr>
<Tr>
<Td>Blog</Td>
<Td><Code>next-mdx-remote</Code></Td>
<Td>/blog/[slug].js</Td>
<Td>I use <Link href="https://github.com/hashicorp/next-mdx-remote" color={linkColor[colorMode]} isExternal>next-mdx-remote</Link> for my blog. Posts are stored in <Code>mdx</Code> files and pre-rendered.</Td>
</Tr>
<Tr>
<Td>Real-Time Statistics</Td>
<Td>Next.js api routes</Td>
<Td>/api/[].js</Td>
<Td>Multiple api routes that interact with the GitHub, YouTube, and Strava api to fetch my real-time social media data using Next.JS <Link href="https://nextjs.org/docs/api-routes/introduction" color={linkColor[colorMode]} isExternal>serverless functions</Link>.</Td>
</Tr>
<Tr>
<Td>Realtime Blog Post View/Like Count</Td>
<Td>Firebase Realtime Db</Td>
<Td>/api</Td>
<Td>I use <Link href="https://firebase.google.com" color={linkColor[colorMode]} isExternal>Google's Firebase</Link> to store view and like counts for my blog posts.</Td>
</Tr>
<Tr>
<Td>Deployment</Td>
<Td>Vercel</Td>
<Td>n/a</Td>
<Td>I use <Link href="https://vercel.com" color={linkColor[colorMode]} isExternal>Vercel</Link> to deploy my app. It's free, fast, integrates with GitHub, and overall a great experience.</Td>
</Tr>
<Tr>
<Td>Domain</Td>
<Td>Namecheap</Td>
<Td>n/a</Td>
<Td>My domain name is bought and stored through <Link color="blue.500" href="https://www.namecheap.com/" isExternal>Namecheap</Link>.</Td>
</Tr>
</Tbody>
</Table>
</Box>
</Box>
)
}
Example #7
Source File: ActivityView.jsx From scaffold-directory with MIT License | 5 votes |
export default function ActivityView() {
const [eventsFeed, setEventFeeds] = useState([]);
const [isLoadingEvents, setIsLoadingEvents] = useState(false);
const { secondaryFontColor } = useCustomColorModes();
useEffect(() => {
const updateEvents = async () => {
setIsLoadingEvents(true);
const events = await getAllEvents(25);
setEventFeeds(events);
setIsLoadingEvents(false);
};
updateEvents();
}, []);
return (
<Container maxW="container.md" centerContent>
<Heading as="h1" mb="4">
Activity feed
</Heading>
<Text color={secondaryFontColor} textAlign="center" mb={10}>
Last 25 things happening at SRE.
</Text>
{isLoadingEvents ? (
<Box w="100%" maxW="500px">
<SkeletonText mt="4" noOfLines={10} spacing="4" />
</Box>
) : (
<Table>
<Thead>
<Tr>
<Th>Builder</Th>
<Th>Time</Th>
<Th>Action</Th>
</Tr>
</Thead>
<Tbody>
{eventsFeed.map(event => (
<EventRow key={`${event.timestamp}_${event.payload.userAddress}`} event={event} />
))}
</Tbody>
</Table>
)}
</Container>
);
}
Example #8
Source File: Cart.js From react-sample-projects with MIT License | 5 votes |
Cart = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const cartItems = useSelector(state => state.cart.cartItems);
const viewProductDetails = (e, item) => {
navigate(`/product/${item.id}`);
};
const deleteItem = (e, item) => {
e.stopPropagation();
e.preventDefault();
dispatch(deleteItemFromCart(item));
};
if (cartItems.length === 0) {
return (
<Flex>
<Box
m={4}
w="100%"
fontWeight="semibold"
letterSpacing="wide"
textAlign="center"
>
You cart empty :(
</Box>
</Flex>
);
}
return (
<Box m={3} p={3}>
<Table variant="simple">
<Thead>
<Tr>
<Th>#</Th>
<Th>Image</Th>
<Th>Title</Th>
<Th isNumeric>Price</Th>
<Th isNumeric>Quantity</Th>
<Th>Action</Th>
</Tr>
</Thead>
<Tbody>
{cartItems.map((item, index) => (
<Tr key={item.id} onClick={e => viewProductDetails(e, item)}>
<Td>{index + 1}</Td>
<Td>
<Avatar size={'sm'} src={item.image} alt={item.title} />
</Td>
<Td>{item.title}</Td>
<Td isNumeric>
${parseFloat(item.price * item.quantity).toFixed(2)}
</Td>
<Td isNumeric>{item.quantity}</Td>
<Td>
<Button onClick={e => deleteItem(e, item)}>Delete</Button>
</Td>
</Tr>
))}
</Tbody>
</Table>
</Box>
);
}
Example #9
Source File: offers.js From idena-web with MIT License | 5 votes |
export default function AdOfferList() {
const {t} = useTranslation()
const queryClient = useQueryClient()
const {data: burntCoins, status: burntCoinsStatus} = useApprovedBurntCoins()
const isFetched = burntCoinsStatus === 'success'
const isEmpty = isFetched && burntCoins.length === 0
const [selectedAd, setSelectedAd] = React.useState({})
const burnDisclosure = useDisclosure()
const {
onOpen: onOpenBurnDisclosure,
onClose: onCloseBurnDisclosure,
} = burnDisclosure
const handlePreviewBurn = React.useCallback(
ad => {
setSelectedAd(ad)
onOpenBurnDisclosure()
},
[onOpenBurnDisclosure]
)
const handleBurn = React.useCallback(() => {
onCloseBurnDisclosure()
queryClient.invalidateQueries(['bcn_burntCoins', []])
}, [onCloseBurnDisclosure, queryClient])
return (
<Layout skipBanner>
<Page>
<PageHeader>
<PageTitle mb={4}>{t('All offers')}</PageTitle>
<PageCloseButton href="/adn/list" />
</PageHeader>
<Table>
<Thead>
<Tr>
<RoundedTh isLeft>{t('Banner/author')}</RoundedTh>
<RoundedTh>{t('Website')}</RoundedTh>
<RoundedTh>{t('Target')}</RoundedTh>
<RoundedTh>{t('Burn')}</RoundedTh>
<RoundedTh isRight />
</Tr>
</Thead>
<Tbody>
{isFetched &&
burntCoins.map(burn => (
<AdOfferListItem
key={burn.key}
burn={burn}
onBurn={handlePreviewBurn}
/>
))}
</Tbody>
</Table>
{isEmpty && (
<Center color="muted" mt="4" w="full">
{t('No active offers')}
</Center>
)}
<BurnDrawer ad={selectedAd} onBurn={handleBurn} {...burnDisclosure} />
</Page>
</Layout>
)
}
Example #10
Source File: SubmissionReviewTableSkeleton.jsx From scaffold-directory with MIT License | 5 votes |
ChallengesTableSkeleton = () => (
<Box overflowX="auto">
<Table mb={4}>
<Thead>
<Tr>
<Th>Builder</Th>
<Th>Challenge</Th>
<Th>Contract</Th>
<Th>Live demo</Th>
<Th>Submitted time</Th>
<Th>Actions</Th>
</Tr>
</Thead>
<Tbody>
{[1, 2].map(lineNumber => {
return (
<Tr key={lineNumber}>
<Td>
<SkeletonAddress w="12.5" fontSize="16" />
</Td>
<Td>
<SkeletonText noOfLines={1} py={4} />
</Td>
<Td>
<SkeletonText noOfLines={1} py={4} />
</Td>
<Td>
<SkeletonText noOfLines={1} py={4} />
</Td>
<Td>
<SkeletonText noOfLines={1} py={4} />
</Td>
<Td>
<Skeleton startColor="blue.100" endColor="blue.500">
<Button type="button" size="xs">
Review
</Button>
</Skeleton>
</Td>
</Tr>
);
})}
</Tbody>
</Table>
</Box>
)
Example #11
Source File: [id].js From idena-web with MIT License | 4 votes |
export default function Details() {
const {t} = useTranslation()
const router = useRouter()
const isDesktop = useIsDesktop()
const [flipView, setFlipView] = useState({
isOpen: false,
})
const {id} = router.query
const {data, isFetching} = useQuery(
['get-certificate-full', id],
() => getCertificate(id, 1),
{
enabled: !!id,
retry: false,
refetchOnWindowFocus: false,
initialData: {
shortFlips: [],
longFlips: [],
},
}
)
const openFlipView = (
hash,
answer,
isCorrect,
withWords,
isCorrectReport,
shouldBeReported
) => {
setFlipView({
isOpen: true,
hash,
answer,
isCorrect,
withWords,
isCorrectReport,
shouldBeReported,
})
}
return (
<Layout>
<Page py={0}>
<Flex direction="column" flex={1} alignSelf="stretch" pb={10}>
<Flex
align="center"
alignSelf="stretch"
justify="space-between"
mt={[4, 8]}
>
<AngleArrowBackIcon
stroke="#578FFF"
display={['block', 'none']}
position="absolute"
left={4}
top={4}
h="28px"
w="28px"
onClick={() => {
router.push('/try')
}}
/>
<PageTitleNew>{t('Training validation report')}</PageTitleNew>
<CloseButton
display={['none', 'flex']}
alignSelf="flex-start"
onClick={() => {
router.push('/try')
}}
/>
</Flex>
<Flex width={['100%', '720px']} direction="column">
{data.actionType === CertificateActionType.Passed && (
<AlertBox>
<Flex align="center">
<RightIcon boxSize={[5, 4]} color="green.500" mr={[3, 2]} />
<Text fontWeight={500}>{t('Passed successfully')}</Text>
</Flex>
</AlertBox>
)}
{data.actionType === CertificateActionType.Failed && (
<AlertBox borderColor="red.050" bg="red.010">
<Flex align="center">
<WarningIcon boxSize={4} color="red.500" mr={2} />
<Text fontWeight={500}>{t('Failed. Please try again')}</Text>
</Flex>
</AlertBox>
)}
<Flex
direction={['column', 'row']}
justifyContent="space-between"
fontSize="md"
align="center"
mt={8}
>
<Flex direction={['column', 'row']} w={['100%', 'auto']}>
<DetailsPoints
title={t('Short score')}
isLoading={isFetching}
value={`${data.shortScore || 0}/6`}
isFailed={data.shortScore < 4}
/>
<DetailsPoints
title={t('Long score')}
isLoading={isFetching}
value={`${data.longScore || 0}/18`}
isFailed={data.longScore < 14}
/>
<DetailsPoints
title={t('Reporting score')}
isLoading={isFetching}
value={`${data.reportScore || 0}/6`}
isFailed={data.reportScore < 4}
mb={[8, 0]}
/>
</Flex>
{data.actionType === CertificateActionType.Passed && (
<Flex w={['100%', 'auto']}>
{isDesktop ? (
<TextLink
href="/certificate/[id]"
as={`/certificate/${id}`}
fontWeight={500}
mr={4}
target="_blank"
>
<CertificateIcon boxSize={5} mr={1} />
{t('Show certificate')}
</TextLink>
) : (
<WideLink
href={`/certificate/${id}`}
target="_blank"
label={t('Show certificate')}
>
<Box
boxSize={8}
backgroundColor="brandBlue.10"
borderRadius="10px"
>
<CertificateIcon boxSize={5} mr={1} mt="6px" ml="6px" />
</Box>
</WideLink>
)}
</Flex>
)}
</Flex>
<Heading
fontSize={['md', 'lg']}
fontWeight="500"
color={['muted', 'brandGray.500']}
mt={[10, 8]}
>
{t('Short session')}
</Heading>
<Flex mt={[0, 5]}>
<Table>
<Thead display={['none', 'table-header-group']}>
<Tr>
<RoundedFlipsTh>
{t('Flips')}
<FlipsThCorner borderLeftRadius="md" />
</RoundedFlipsTh>
<RoundedFlipsTh w={32}>
{t('Answers')}
<FlipsThCorner borderRightRadius="md" />
</RoundedFlipsTh>
</Tr>
</Thead>
<Tbody>
{isFetching
? new Array(6).fill(0).map((_, idx) => (
<Tr key={idx}>
<Td colSpan={2} px={0} py={2}>
<Skeleton h={7} />
</Td>
</Tr>
))
: data.shortFlips.map(({hash, answer, correct}) => (
<Tr key={hash}>
<FlipsValueTd>
<ShortFlipWithIcon
hash={hash}
onClick={() =>
openFlipView(hash, answer, correct)
}
/>
</FlipsValueTd>
<FlipsValueTd w={['60px', 'auto']}>
<Flex alignItems="center">
{correct ? (
<RightIcon color="green.500" boxSize={5} />
) : (
<WrongIcon color="red.500" boxSize={5} />
)}
<Flex fontSize={['base', 'md']} ml={[1, 2]}>
{GetAnswerTitle(t, answer)}
</Flex>
</Flex>
</FlipsValueTd>
</Tr>
))}
</Tbody>
</Table>
</Flex>
<Heading
fontSize={['md', 'lg']}
fontWeight="500"
color={['muted', 'brandGray.500']}
mt={[10, 8]}
>
{t('Long session')}
</Heading>
<Flex mt={[0, 5]}>
<Table style={{tableLayout: 'fixed'}}>
<Thead display={['none', 'table-header-group']}>
<Tr>
<RoundedFlipsTh w="35%">
{t('Flips')}
<FlipsThCorner borderLeftRadius="md" />
</RoundedFlipsTh>
<FlipsTh w={32}>{t('Answers')}</FlipsTh>
<FlipsTh>{t('Qualification')}</FlipsTh>
<RoundedFlipsTh>
{t('Reporting reason')}
<FlipsThCorner borderRightRadius="md" />
</RoundedFlipsTh>
</Tr>
</Thead>
<Tbody>
{isFetching
? new Array(6).fill(0).map((_, idx) => (
<Tr key={idx}>
<Td colSpan={4} px={0} py={2}>
<Skeleton h={7} />
</Td>
</Tr>
))
: data.longFlips.map(
({
hash,
answer,
correct,
correctReport,
wrongWords,
reason,
}) => (
<>
<Tr position={['relative', 'initial']} key={hash}>
<FlipsValueTd
borderBottom={[0, '1px solid #e8eaed']}
>
<LongFlipWithIcon
hash={hash}
onClick={() =>
openFlipView(
hash,
answer,
correct,
true,
correctReport,
reason !== 0
)
}
/>
</FlipsValueTd>
<FlipsValueTd
borderBottom={[0, '1px solid #e8eaed']}
w={['75px', 'auto']}
>
<Flex direction={['column', 'row']}>
<Flex alignItems="center">
{correct ? (
<RightIcon
color="green.500"
boxSize={5}
/>
) : (
<WrongIcon color="red.500" boxSize={5} />
)}
<Text
textOverflow="ellipsis"
overflow="hidden"
whiteSpace="nowrap"
fontSize={['base', 'md']}
ml={[1, 2]}
>
{GetAnswerTitle(t, answer)}
</Text>
</Flex>
<Text
display={['block', 'none']}
color="muted"
fontSize="md"
fontWeight={500}
>
{t('Answer')}
</Text>
</Flex>
</FlipsValueTd>
<FlipsValueTd
borderBottom={[0, '1px solid #e8eaed']}
w={['90px', 'auto']}
>
<Flex direction={['column', 'row']}>
<Flex alignItems="center">
{correctReport ? (
<RightIcon
color="green.500"
boxSize={5}
/>
) : (
<WrongIcon color="red.500" boxSize={5} />
)}
<Text
textOverflow="ellipsis"
overflow="hidden"
whiteSpace="nowrap"
fontSize={['base', 'md']}
ml={[1, 2]}
>
{wrongWords
? t('Reported')
: t('Not reported')}
</Text>
</Flex>
<Text
display={['block', 'none']}
color="muted"
fontSize="md"
fontWeight={500}
>
{t('Qualification')}
</Text>
</Flex>
</FlipsValueTd>
<FlipsValueTd display={['none', 'table-cell']}>
{GetReasonDesc(t, reason)}
</FlipsValueTd>
</Tr>
<FlipsHiddenDescRow>
<Flex
direction="column"
w="100%"
onClick={() =>
openFlipView(
hash,
answer,
correct,
true,
correctReport,
reason !== 0
)
}
>
<Text fontSize="base" fontWeight={500}>
{GetReasonDesc(t, reason)}
</Text>
<Text
color="muted"
fontSize="md"
fontWeight={500}
>
{t('Reason')}
</Text>
</Flex>
</FlipsHiddenDescRow>
</>
)
)}
</Tbody>
</Table>
</Flex>
</Flex>
</Flex>
<FlipView {...flipView} onClose={() => setFlipView({isOpen: false})} />
</Page>
</Layout>
)
}
Example #12
Source File: VaultItemEdit.js From web-client with Apache License 2.0 | 4 votes |
VaultItemEdit = () => {
const { projectId, vaultItemId } = useParams();
const navigate = useNavigate();
const [item, setVaultItem] = useState(new Vault());
const [password, setPassword] = useState(null);
const onVaultItemFormChange = ev => {
const value = ev.target.type === 'checkbox' ? ev.target.checked : ev.target.value;
setVaultItem({ ...item, [ev.target.name]: value });
}
const onFormSubmit = ev => {
ev.preventDefault();
item.password = password;
secureApiFetch(`/vault/${projectId}/${vaultItemId}`, { method: 'PUT', body: JSON.stringify(item) })
.then(resp => {
if (resp.status === 201) {
setVaultItem(new Vault());
setPassword(null);
actionCompletedToast(`The vault item has been modified.`);
navigate(`/projects/${projectId}`);
} else {
errorToast("The vault item could not be saved. Review the form data or check the application logs.")
}
})
}
const onPasswordProvided = ev => {
ev.preventDefault();
secureApiFetch(`/vault/${projectId}/${vaultItemId}`, { method: 'POST', body: JSON.stringify({ 'password': password }) })
.then(response => response.json())
.then(json => {
if (json['success'] === false) {
errorToast("Seems like a wrong password.");
setPassword(null);
}
else {
var newItem = new Vault();
newItem.name = json['name'];
newItem.note = json['note'];
newItem.value = json['value'];
newItem.type = json['type'];
newItem.reportable = json['reportable'];
setVaultItem(newItem);
actionCompletedToast(`The vault item "${newItem.name}" has been loaded.`);
}
})
.catch(err => {
errorToast(err);
setPassword(null);
})
}
const onPasswordFormChanged = ev => {
setPassword(ev.target.value);
}
return <div>
{item.name !== "" && <>
<form onSubmit={onFormSubmit}>
<h3>Vault item</h3>
<Table>
<Thead>
<Tr>
<Th>Type</Th>
<Th>Name</Th>
<Th>Note</Th>
<Th>Value</Th>
<Th>Reportable</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td>
<Select name="type" onChange={onVaultItemFormChange} value={item.type || ""} isRequired>
<option value="password">Password</option>
<option value="note">Note</option>
<option value="token">Token</option>
<option value="key">Key</option>
</Select>
</Td>
<Td>
<Input type="text" name="name" onChange={onVaultItemFormChange} value={item.name || ""} isRequired />
</Td>
<Td>
<Input type="text" name="note" onChange={onVaultItemFormChange} value={item.note || ""} />
</Td>
<Td>
<Input type="text" name="value" onChange={onVaultItemFormChange} value={item.value || ""} isRequired />
</Td>
<Td>
<Checkbox name="reportable" onChange={onVaultItemFormChange} isChecked={item.reportable} />
</Td>
<Td>
<Button type="submit">Update</Button>
</Td>
</Tr>
</Tbody>
</Table>
</form>
</>}
{item.name === "" && <>
<h3>Please provide password</h3>
<form onSubmit={onPasswordProvided}>
<Input type="password" name="password" onChange={onPasswordFormChanged} value={password || ""} isRequired />
<Button type="submit">Send</Button>
</form>
</>}
</div>
}
Example #13
Source File: view.js From idena-web with MIT License | 4 votes |
export default function ViewVotingPage() {
const {t, i18n} = useTranslation()
const [, {addVote}] = useDeferredVotes()
const toast = useToast()
const {
query: {id},
push: redirect,
} = useRouter()
const {epoch} = useEpoch() ?? {epoch: -1}
const {coinbase, privateKey} = useAuthState()
const {
data: {balance: identityBalance},
} = useBalance()
const [current, send, service] = useMachine(viewVotingMachine, {
actions: {
onError: (context, {data: {message}}) => {
toast({
status: 'error',
// eslint-disable-next-line react/display-name
render: () => (
<Toast title={humanError(message, context)} status="error" />
),
})
},
addVote: (_, {data: {vote}}) => addVote(vote),
},
})
React.useEffect(() => {
send('RELOAD', {id, epoch, address: coinbase})
}, [coinbase, epoch, id, send])
const toDna = toLocaleDna(i18n.language)
const {
title,
desc,
contractHash,
status,
balance = 0,
contractBalance = Number(balance),
votingMinPayment = 0,
publicVotingDuration = 0,
quorum = 20,
committeeSize,
options = [],
votes = [],
voteProofsCount,
finishDate,
finishCountingDate,
selectedOption,
winnerThreshold = 50,
balanceUpdates,
ownerFee,
totalReward,
estimatedOracleReward,
estimatedMaxOracleReward = estimatedOracleReward,
isOracle,
minOracleReward,
estimatedTotalReward,
pendingVote,
adCid,
issuer,
} = current.context
const [
{canProlong, canFinish, canTerminate, isFetching: actionsIsFetching},
refetchActions,
] = useOracleActions(id)
const isLoaded = !current.matches('loading')
const sameString = a => b => areSameCaseInsensitive(a, b)
const eitherIdleState = (...states) =>
eitherState(current, ...states.map(s => `idle.${s}`.toLowerCase())) ||
states.some(sameString(status))
const isClosed = eitherIdleState(
VotingStatus.Archived,
VotingStatus.Terminated
)
const didDetermineWinner = hasWinner({
votes,
votesCount: voteProofsCount,
winnerThreshold,
quorum,
committeeSize,
finishCountingDate,
})
const isMaxWinnerThreshold = winnerThreshold === 100
const accountableVoteCount = sumAccountableVotes(votes)
const {data: ad} = useIpfsAd(adCid)
const adPreviewDisclosure = useDisclosure()
const isValidAdVoting = React.useMemo(
() => validateAdVoting({ad, voting: current.context}) === false,
[ad, current.context]
)
const isMaliciousAdVoting = ad && isValidAdVoting
return (
<>
<Layout showHamburger={false}>
<Page pt={8}>
<Stack spacing={10}>
<VotingSkeleton isLoaded={isLoaded} h={6}>
<Stack isInline spacing={2} align="center">
<VotingStatusBadge status={status} fontSize="md">
{t(mapVotingStatus(status))}
</VotingStatusBadge>
<Box
as={VotingBadge}
bg="gray.100"
color="muted"
fontSize="md"
cursor="pointer"
pl="1/2"
transition="color 0.2s ease"
_hover={{
color: 'brandGray.500',
}}
onClick={() => {
openExternalUrl(
`https://scan.idena.io/contract/${contractHash}`
)
}}
>
<Stack isInline spacing={1} align="center">
<Avatar size={5} address={contractHash} />
<Text>{contractHash}</Text>
</Stack>
</Box>
<CloseButton
sx={{
'&': {
marginLeft: 'auto!important',
},
}}
onClick={() => redirect('/oracles/list')}
/>
</Stack>
</VotingSkeleton>
<Stack isInline spacing={10} w="full">
<Box minWidth="lg" maxW="lg">
<Stack spacing={6}>
<VotingSkeleton isLoaded={isLoaded}>
<Stack
spacing={8}
borderRadius="md"
bg="gray.50"
py={8}
px={10}
>
<Stack spacing={4}>
<Heading
overflow="hidden"
fontSize={21}
fontWeight={500}
display="-webkit-box"
sx={{
'&': {
WebkitBoxOrient: 'vertical',
WebkitLineClamp: '2',
},
}}
>
{isMaliciousAdVoting
? t('Please reject malicious ad')
: title}
</Heading>
{ad ? (
<>
{isMaliciousAdVoting ? (
<MaliciousAdOverlay>
<OracleAdDescription ad={ad} />
</MaliciousAdOverlay>
) : (
<OracleAdDescription ad={ad} />
)}
</>
) : (
<Text
isTruncated
lineHeight="tall"
whiteSpace="pre-wrap"
>
<Linkify
onClick={url => {
send('FOLLOW_LINK', {url})
}}
>
{desc}
</Linkify>
</Text>
)}
</Stack>
<Flex>
{adCid && (
<IconButton
icon={<ViewIcon boxSize={4} />}
_hover={{background: 'transparent'}}
onClick={adPreviewDisclosure.onOpen}
>
{t('Preview')}
</IconButton>
)}
<GoogleTranslateButton
phrases={[
title,
desc &&
encodeURIComponent(desc?.replace(/%/g, '%25')),
options.map(({value}) => value).join('\n'),
]}
locale={i18n.language}
alignSelf="start"
/>
</Flex>
<Divider orientation="horizontal" />
{isLoaded && <VotingPhase service={service} />}
</Stack>
</VotingSkeleton>
{eitherIdleState(
VotingStatus.Pending,
VotingStatus.Starting,
VotingStatus.Open,
VotingStatus.Voting,
VotingStatus.Voted,
VotingStatus.Prolonging
) && (
<VotingSkeleton isLoaded={isLoaded}>
{isMaliciousAdVoting ? (
<>
{eitherIdleState(VotingStatus.Voted) ? (
<Box>
<Text color="muted" fontSize="sm" mb={3}>
{t('Choose an option to vote')}
</Text>
<Stack spacing={3}>
{/* eslint-disable-next-line no-shadow */}
{options.map(({id, value}) => {
const isMine = id === selectedOption
return (
<Stack
isInline
spacing={2}
align="center"
bg={isMine ? 'blue.012' : 'gray.50'}
borderRadius="md"
minH={8}
px={3}
py={2}
zIndex={1}
>
<Flex
align="center"
justify="center"
bg={
isMine
? 'brandBlue.500'
: 'transparent'
}
borderRadius="full"
borderWidth={isMine ? 0 : '4px'}
borderColor="gray.100"
color="white"
w={4}
h={4}
>
{isMine && <OkIcon boxSize={3} />}
</Flex>
<Text
isTruncated
maxW="sm"
title={value.length > 50 ? value : ''}
>
{value}
</Text>
</Stack>
)
})}
</Stack>
</Box>
) : null}
</>
) : (
<Box>
<Text color="muted" fontSize="sm" mb={3}>
{t('Choose an option to vote')}
</Text>
{eitherIdleState(VotingStatus.Voted) ? (
<Stack spacing={3}>
{/* eslint-disable-next-line no-shadow */}
{options.map(({id, value}) => {
const isMine = id === selectedOption
return (
<Stack
isInline
spacing={2}
align="center"
bg={isMine ? 'blue.012' : 'gray.50'}
borderRadius="md"
minH={8}
px={3}
py={2}
zIndex={1}
>
<Flex
align="center"
justify="center"
bg={
isMine ? 'brandBlue.500' : 'transparent'
}
borderRadius="full"
borderWidth={isMine ? 0 : '4px'}
borderColor="gray.100"
color="white"
w={4}
h={4}
>
{isMine && <OkIcon boxSize={3} />}
</Flex>
<Text
isTruncated
maxW="sm"
title={value.length > 50 ? value : ''}
>
{value}
</Text>
</Stack>
)
})}
</Stack>
) : (
<RadioGroup
value={String(selectedOption)}
onChange={value => {
send('SELECT_OPTION', {
option: Number(value),
})
}}
>
<Stack spacing={2}>
{/* eslint-disable-next-line no-shadow */}
{options.map(({id, value}) => (
<VotingOption
key={id}
value={String(id)}
isDisabled={eitherIdleState(
VotingStatus.Pending,
VotingStatus.Starting,
VotingStatus.Voted
)}
annotation={
isMaxWinnerThreshold
? null
: t('{{count}} min. votes required', {
count: toPercent(
winnerThreshold / 100
),
})
}
>
{value}
</VotingOption>
))}
</Stack>
</RadioGroup>
)}
</Box>
)}
</VotingSkeleton>
)}
{eitherIdleState(
VotingStatus.Counting,
VotingStatus.Finishing,
VotingStatus.Archived,
VotingStatus.Terminating,
VotingStatus.Terminated
) && (
<VotingSkeleton isLoaded={isLoaded}>
<Stack spacing={3}>
<Text color="muted" fontSize="sm">
{t('Voting results')}
</Text>
<VotingResult votingService={service} spacing={3} />
</Stack>
</VotingSkeleton>
)}
<VotingSkeleton isLoaded={!actionsIsFetching}>
<Flex justify="space-between" align="center">
<Stack isInline spacing={2}>
{eitherIdleState(VotingStatus.Pending) && (
<PrimaryButton
loadingText={t('Launching')}
onClick={() => {
send('REVIEW_START_VOTING', {
from: coinbase,
})
}}
>
{t('Launch')}
</PrimaryButton>
)}
{eitherIdleState(VotingStatus.Open) &&
(isOracle ? (
<PrimaryButton
onClick={() => {
if (isMaliciousAdVoting) {
send('FORCE_REJECT')
}
send('REVIEW')
}}
>
{isMaliciousAdVoting ? t('Reject') : t('Vote')}
</PrimaryButton>
) : (
<Box>
<Tooltip
label={t(
'This vote is not available to you. Only validated identities randomly selected to the committee can vote.'
)}
placement="top"
zIndex="tooltip"
>
<PrimaryButton isDisabled>
{t('Vote')}
</PrimaryButton>
</Tooltip>
</Box>
))}
{eitherIdleState(VotingStatus.Counting) && canFinish && (
<PrimaryButton
isLoading={current.matches(
`mining.${VotingStatus.Finishing}`
)}
loadingText={t('Finishing')}
onClick={() => send('FINISH', {from: coinbase})}
>
{didDetermineWinner
? t('Finish voting')
: t('Claim refunds')}
</PrimaryButton>
)}
{eitherIdleState(
VotingStatus.Open,
VotingStatus.Voting,
VotingStatus.Voted,
VotingStatus.Counting
) &&
canProlong && (
<PrimaryButton
onClick={() => send('REVIEW_PROLONG_VOTING')}
>
{t('Prolong voting')}
</PrimaryButton>
)}
{(eitherIdleState(
VotingStatus.Voted,
VotingStatus.Voting
) ||
(eitherIdleState(VotingStatus.Counting) &&
!canProlong &&
!canFinish)) && (
<PrimaryButton as={Box} isDisabled>
{t('Vote')}
</PrimaryButton>
)}
{!eitherIdleState(
VotingStatus.Terminated,
VotingStatus.Terminating
) &&
canTerminate && (
<PrimaryButton
colorScheme="red"
variant="solid"
_active={{}}
onClick={() => send('TERMINATE')}
>
{t('Terminate')}
</PrimaryButton>
)}
</Stack>
<Stack isInline spacing={3} align="center">
{eitherIdleState(
VotingStatus.Archived,
VotingStatus.Terminated
) &&
!didDetermineWinner && (
<Text color="red.500">
{t('No winner selected')}
</Text>
)}
<VDivider />
<Stack isInline spacing={2} align="center">
{didDetermineWinner ? (
<UserTickIcon color="muted" boxSize={4} />
) : (
<UserIcon color="muted" boxSize={4} />
)}
<Text as="span">
{/* eslint-disable-next-line no-nested-ternary */}
{eitherIdleState(VotingStatus.Counting) ? (
<>
{t('{{count}} published votes', {
count: accountableVoteCount,
})}{' '}
{t('out of {{count}}', {
count: voteProofsCount,
})}
</>
) : eitherIdleState(
VotingStatus.Pending,
VotingStatus.Open,
VotingStatus.Voting,
VotingStatus.Voted
) ? (
t('{{count}} votes', {
count: voteProofsCount,
})
) : (
t('{{count}} published votes', {
count: accountableVoteCount,
})
)}
</Text>
</Stack>
</Stack>
</Flex>
</VotingSkeleton>
<VotingSkeleton isLoaded={isLoaded}>
<Stack spacing={5}>
<Box>
<Text fontWeight={500}>{t('Recent transactions')}</Text>
</Box>
<Table style={{tableLayout: 'fixed', fontWeight: 500}}>
<Thead>
<Tr>
<RoundedTh isLeft>{t('Transaction')}</RoundedTh>
<RoundedTh>{t('Date and time')}</RoundedTh>
<RoundedTh isRight textAlign="right">
{t('Amount')}
</RoundedTh>
</Tr>
</Thead>
<Tbody>
{balanceUpdates.map(
({
hash,
type,
timestamp,
from,
amount,
fee,
tips,
balanceChange = 0,
contractCallMethod,
}) => {
const isSender = areSameCaseInsensitive(
from,
coinbase
)
const txCost =
(isSender ? -amount : 0) + balanceChange
const totalTxCost =
txCost - ((isSender ? fee : 0) + tips)
const isCredit = totalTxCost > 0
const color =
// eslint-disable-next-line no-nested-ternary
totalTxCost === 0
? 'brandGray.500'
: isCredit
? 'blue.500'
: 'red.500'
return (
<Tr key={hash}>
<OraclesTxsValueTd>
<Stack isInline>
<Flex
align="center"
justify="center"
bg={isCredit ? 'blue.012' : 'red.012'}
color={color}
borderRadius="lg"
minH={8}
minW={8}
>
{isSender ? (
<ArrowUpIcon boxSize={5} />
) : (
<ArrowDownIcon boxSize={5} />
)}
</Flex>
<Box isTruncated>
{contractCallMethod ? (
<Text>
{
ContractCallMethod[
contractCallMethod
]
}
</Text>
) : (
<Text>
{ContractTransactionType[type]}
</Text>
)}
<SmallText isTruncated title={from}>
{hash}
</SmallText>
</Box>
</Stack>
</OraclesTxsValueTd>
<OraclesTxsValueTd>
<Text>
{new Date(timestamp).toLocaleString()}
</Text>
</OraclesTxsValueTd>
<OraclesTxsValueTd textAlign="right">
<Text
color={color}
overflowWrap="break-word"
>
{toLocaleDna(i18n.language, {
signDisplay: 'exceptZero',
})(txCost)}
</Text>
{isSender && (
<SmallText>
{t('Fee')} {toDna(fee + tips)}
</SmallText>
)}
</OraclesTxsValueTd>
</Tr>
)
}
)}
{balanceUpdates.length === 0 && (
<Tr>
<OraclesTxsValueTd colSpan={3}>
<FillCenter py={12}>
<Stack spacing={4} align="center">
<CoinsLgIcon
boxSize={20}
color="gray.100"
/>
<Text color="muted">
{t('No transactions')}
</Text>
</Stack>
</FillCenter>
</OraclesTxsValueTd>
</Tr>
)}
</Tbody>
</Table>
</Stack>
</VotingSkeleton>
</Stack>
</Box>
<VotingSkeleton isLoaded={isLoaded} h={isLoaded ? 'auto' : 'lg'}>
<Box mt={3}>
<Box mt={-2} mb={4}>
<IconButton
icon={<RefreshIcon boxSize={5} />}
px={1}
pr={3}
_focus={null}
onClick={() => {
send('REFRESH')
refetchActions()
}}
>
{t('Refresh')}
</IconButton>
</Box>
{!isClosed && (
<Stat mb={8}>
<StatLabel as="div" color="muted" fontSize="md">
<Stack isInline spacing={2} align="center">
<StarIcon boxSize={4} color="white" />
<Text fontWeight={500}>{t('Prize pool')}</Text>
</Stack>
</StatLabel>
<StatNumber fontSize="base" fontWeight={500}>
{toDna(estimatedTotalReward)}
</StatNumber>
<Box mt={1}>
<IconButton
icon={<AddFundIcon boxSize={5} />}
onClick={() => {
send('ADD_FUND')
}}
>
{t('Add funds')}
</IconButton>
</Box>
</Stat>
)}
<Stack spacing={6}>
{!isClosed && (
<Stat>
<StatLabel color="muted" fontSize="md">
<Tooltip
label={
// eslint-disable-next-line no-nested-ternary
Number(votingMinPayment) > 0
? isMaxWinnerThreshold
? t('Deposit will be refunded')
: t(
'Deposit will be refunded if your vote matches the majority'
)
: t('Free voting')
}
placement="top"
>
<Text
as="span"
borderBottom="dotted 1px"
borderBottomColor="muted"
cursor="help"
>
{t('Voting deposit')}
</Text>
</Tooltip>
</StatLabel>
<StatNumber fontSize="base" fontWeight={500}>
{toDna(votingMinPayment)}
</StatNumber>
</Stat>
)}
{!isClosed && (
<Stat>
<StatLabel color="muted" fontSize="md">
<Tooltip
label={t('Including your Voting deposit')}
placement="top"
>
<Text
as="span"
borderBottom="dotted 1px"
borderBottomColor="muted"
cursor="help"
>
{t('Min reward')}
</Text>
</Tooltip>
</StatLabel>
<StatNumber fontSize="base" fontWeight={500}>
{toDna(estimatedOracleReward)}
</StatNumber>
</Stat>
)}
{!isClosed && (
<Stat>
<StatLabel color="muted" fontSize="md">
{isMaxWinnerThreshold ? (
<Text as="span">{t('Your max reward')}</Text>
) : (
<Tooltip
label={t(
`Including a share of minority voters' deposit`
)}
placement="top"
>
<Text
as="span"
borderBottom="dotted 1px"
borderBottomColor="muted"
cursor="help"
>
{t('Max reward')}
</Text>
</Tooltip>
)}
</StatLabel>
<StatNumber fontSize="base" fontWeight={500}>
{toDna(estimatedMaxOracleReward)}
</StatNumber>
</Stat>
)}
<AsideStat
label={t('Committee size')}
value={t('{{committeeSize}} oracles', {committeeSize})}
/>
<AsideStat
label={t('Quorum required')}
value={t('{{count}} votes', {
count: quorumVotesCount({quorum, committeeSize}),
})}
/>
<AsideStat
label={t('Majority threshold')}
value={
isMaxWinnerThreshold
? t('N/A')
: toPercent(winnerThreshold / 100)
}
/>
{isClosed && totalReward && (
<AsideStat
label={t('Prize paid')}
value={toDna(totalReward)}
/>
)}
</Stack>
</Box>
</VotingSkeleton>
</Stack>
</Stack>
</Page>
</Layout>
<VoteDrawer
isOpen={
eitherState(current, 'review', `mining.${VotingStatus.Voting}`) &&
!eitherState(
current,
`mining.${VotingStatus.Voting}.reviewPendingVote`
)
}
onClose={() => {
send('CANCEL')
}}
// eslint-disable-next-line no-shadow
option={options.find(({id}) => id === selectedOption)?.value}
from={coinbase}
to={contractHash}
deposit={votingMinPayment}
publicVotingDuration={publicVotingDuration}
finishDate={finishDate}
finishCountingDate={finishCountingDate}
isLoading={current.matches(`mining.${VotingStatus.Voting}`)}
onVote={() => {
send('VOTE', {privateKey})
}}
/>
<AddFundDrawer
isOpen={eitherState(
current,
'funding',
`mining.${VotingStatus.Funding}`
)}
onClose={() => {
send('CANCEL')
}}
from={coinbase}
to={contractHash}
available={identityBalance}
ownerFee={ownerFee}
isLoading={current.matches(`mining.${VotingStatus.Funding}`)}
onAddFund={({amount}) => {
send('ADD_FUND', {amount, privateKey})
}}
/>
<LaunchDrawer
isOpen={eitherState(
current,
`idle.${VotingStatus.Pending}.review`,
`mining.${VotingStatus.Starting}`
)}
onClose={() => {
send('CANCEL')
}}
balance={contractBalance}
requiredBalance={votingMinBalance(minOracleReward, committeeSize)}
ownerFee={ownerFee}
from={coinbase}
available={identityBalance}
isLoading={current.matches(`mining.${VotingStatus.Starting}`)}
onLaunch={({amount}) => {
send('START_VOTING', {amount, privateKey})
}}
/>
<FinishDrawer
isOpen={eitherState(
current,
`idle.${VotingStatus.Counting}.finish`,
`mining.${VotingStatus.Finishing}`
)}
onClose={() => {
send('CANCEL')
}}
from={coinbase}
available={identityBalance}
isLoading={current.matches(`mining.${VotingStatus.Finishing}`)}
onFinish={() => {
send('FINISH', {privateKey})
}}
hasWinner={didDetermineWinner}
/>
<ProlongDrawer
isOpen={eitherState(
current,
'prolong',
`mining.${VotingStatus.Prolonging}`
)}
onClose={() => {
send('CANCEL')
}}
from={coinbase}
available={identityBalance}
isLoading={current.matches(`mining.${VotingStatus.Prolonging}`)}
onProlong={() => {
send('PROLONG_VOTING', {privateKey})
}}
/>
<TerminateDrawer
isOpen={eitherState(
current,
`idle.terminating`,
`mining.${VotingStatus.Terminating}`
)}
onClose={() => {
send('CANCEL')
}}
contractAddress={contractHash}
isLoading={current.matches(`mining.${VotingStatus.Terminating}`)}
onTerminate={() => {
send('TERMINATE', {privateKey})
}}
/>
{pendingVote && (
<ReviewNewPendingVoteDialog
isOpen={eitherState(
current,
`mining.${VotingStatus.Voting}.reviewPendingVote`
)}
onClose={() => {
send('GOT_IT')
}}
vote={pendingVote}
startCounting={finishDate}
finishCounting={finishCountingDate}
/>
)}
{adCid && (
<AdPreview
ad={{...ad, author: issuer}}
isMalicious={isMaliciousAdVoting}
{...adPreviewDisclosure}
/>
)}
<Dialog
isOpen={eitherIdleState('redirecting')}
onClose={() => send('CANCEL')}
>
<DialogHeader>{t('Leaving Idena')}</DialogHeader>
<DialogBody>
<Text>{t(`You're about to leave Idena.`)}</Text>
<Text>{t(`Are you sure?`)}</Text>
</DialogBody>
<DialogFooter>
<SecondaryButton onClick={() => send('CANCEL')}>
{t('Cancel')}
</SecondaryButton>
<PrimaryButton onClick={() => send('CONTINUE')}>
{t('Continue')}
</PrimaryButton>
</DialogFooter>
</Dialog>
</>
)
}
Example #14
Source File: List.js From web-client with Apache License 2.0 | 4 votes |
ReportTemplatesList = () => {
const [templates, refetchTemplates] = useFetch('/reports/templates')
const destroy = useDelete('/reports/', refetchTemplates);
const deleteTemplate = (ev, templateId) => {
ev.stopPropagation();
destroy(templateId);
}
const { isOpen: isAddReportTemplateDialogOpen, onOpen: openAddReportTemplateDialog, onClose: closeAddReportTemplateDialog } = useDisclosure();
const onReportTemplateFormSaved = () => {
refetchTemplates();
closeAddReportTemplateDialog();
}
const handleDownload = (reportId) => {
secureApiFetch(`/attachments/${reportId}`, { method: 'GET', headers: {} })
.then(resp => {
const contentDispositionHeader = resp.headers.get('Content-Disposition');
const filenameRe = new RegExp(/filename="(.*)";/)
const filename = filenameRe.exec(contentDispositionHeader)[1]
return Promise.all([resp.blob(), filename]);
})
.then((values) => {
const blob = values[0];
const filename = values[1];
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
})
}
const safeResolveMime = mimeType => {
try {
return resolveMime(mimeType)['name']
} catch (err) {
console.error(err);
return mimeType;
}
}
return <>
<PageTitle value="Report templates" />
<div className='heading'>
<Breadcrumb>
<Link to="/reports">Reports</Link>
</Breadcrumb>
<ReportModalDialog isOpen={isAddReportTemplateDialogOpen} onSubmit={onReportTemplateFormSaved} onCancel={closeAddReportTemplateDialog} />
<CreateButton onClick={openAddReportTemplateDialog}>Add report template...</CreateButton>
</div>
<Title title='Report templates' icon={<IconDocumentDuplicate />} />
<Alert status="info">
<AlertIcon />
Needing some inspiration? Have a look at hundred of penetration test reports available at <ExternalLink href="http://pentestreports.com/">http://pentestreports.com/</ExternalLink>
</Alert>
<Alert status="info">
<AlertIcon />
Visit this <ExternalLink href={UserManualUrl + 'reports/report-template-variables.html'}>user manual's page</ExternalLink> if you want to find out which variables are available to your report templates.
</Alert>
{!templates ? <Loading /> :
<Table variant="simple">
<Thead>
<Tr>
<Th style={{ width: '190px' }}>Name</Th>
<Th>Description</Th>
<Th style={{ width: '190px' }}>File name</Th>
<Th>Mime type</Th>
<Th>Downloads</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{templates.length === 0 ?
<Tr><Td colSpan={3}><NoResults /></Td></Tr>
:
templates.map((template) =>
<Tr key={template.id}>
<Td>{template.version_name}</Td>
<Td><EmptyField value={template.version_description} /></Td>
<Td>{template.client_file_name}</Td>
<Td><span title={safeResolveMime(template.file_mimetype)}>{template.file_mimetype}</span></Td>
<Td>
<SecondaryButton onClick={() => handleDownload(template.attachment_id)}>
<IconDocument /> DOCX
</SecondaryButton>
</Td>
<Td textAlign="right">
<DeleteIconButton disabled={template.generated_by_uid === 0} title={template.generated_by_uid === 0 ? "System templates cannot be deleted" : ""} onClick={ev => deleteTemplate(ev, template.id)} />
</Td>
</Tr>
)
}
</Tbody>
</Table>
}
</>
}
Example #15
Source File: rent.js From idena-web with MIT License | 4 votes |
export default function Rent() {
const router = useRouter()
const {t} = useTranslation()
const {coinbase} = useAuthState()
const buySharedNodeDisclosure = useDisclosure()
const [state, setState] = useState(0)
const [checkedProviders, setCheckedProviders] = useState([])
const {
data: indexerData,
isFetched: indexerIsFetched,
isLoading: indexerIsLoading,
} = useQuery(['last-block'], () => getLastBlock(), {
retry: false,
refetchOnWindowFocus: false,
})
const {data: identity, isLoading: identityIsLoading} = useQuery(
['fetch-identity', coinbase],
() => fetchIdentity(coinbase, true),
{
enabled: !!coinbase,
refetchOnWindowFocus: false,
}
)
const {data: providers, isLoading: providersIsLoading} = useQuery(
['providers'],
getProviders,
{
initialData: [],
enabled: !!indexerIsFetched,
refetchOnWindowFocus: false,
}
)
const indexerLastBlock = indexerData?.height || 0
useEffect(() => {
async function updateStatus() {
const shuffled = shuffle(providers.filter(x => Boolean(x.slots)))
shuffled.forEach(provider => {
checkProviderSyncing(provider.data.url)
.then(response =>
setCheckedProviders(prev => {
const blocksLeft = indexerLastBlock - response?.currentBlock
return mergeProviders(prev, {
...provider,
duration: response.duration,
blocksLeft,
status:
blocksLeft > SYNCING_DIFF
? ProviderStatus.OutOfSync
: ProviderStatus.Success,
})
})
)
.catch(() =>
setCheckedProviders(prev =>
mergeProviders(prev, {
...provider,
duration: MAX_DURATION,
status: ProviderStatus.Error,
})
)
)
})
}
if (providers.length) updateStatus()
}, [indexerLastBlock, providers])
const isLoading = indexerIsLoading || identityIsLoading || providersIsLoading
const isDesktop = useIsDesktop()
const {
isOpen: isOpenRentDetailDrawer,
onOpen: onOpenRentDetailDrawer,
onClose: onCloseRentDetailDrawer,
} = useDisclosure()
const selectedProvider = checkedProviders.length && checkedProviders[state]
return (
<Layout canRedirect={false}>
<Page mb={14} pt={[4, 6]}>
<Box w="full">
<Flex align="center" justify="space-between">
<AngleArrowBackIcon
stroke="#578FFF"
display={['block', 'none']}
position="absolute"
left={4}
top={4}
h="28px"
w="28px"
onClick={() => {
router.back()
}}
/>
<PageTitleNew>{t('Rent a shared node')}</PageTitleNew>
<CloseButton
display={['none', 'flex']}
onClick={() => router.back()}
/>
</Flex>
<Box>
<Table>
<Thead display={['none', 'table-header-group']}>
<Tr>
<RoundedTh isLeft width={rem(40)}></RoundedTh>
<RoundedTh>{t('Node URL')}</RoundedTh>
<RoundedTh>{t('Owner')}</RoundedTh>
<RoundedTh>{t('Location')}</RoundedTh>
<RoundedTh>{t('Latency, sec')}</RoundedTh>
<RoundedTh textAlign="right">
{t('Slots available')}
</RoundedTh>
<RoundedTh isRight textAlign="right">
{t('Price per validation')}
</RoundedTh>
</Tr>
</Thead>
<Tbody>
{isLoading
? new Array(10).fill(0).map((_, idx) => (
<Tr key={idx}>
<Td colSpan={7} px={0}>
<Skeleton h={[32, 8]} />
</Td>
</Tr>
))
: checkedProviders.map((p, idx) => (
<Tr key={idx}>
<Td display={['none', 'table-cell']}>
<Radio
isChecked={state === idx}
onClick={() => setState(idx)}
borderColor="#d2d4d9"
/>
</Td>
<Td
borderBottom={['solid 0px', 'solid 1px #e8eaed']}
px={[0, 3]}
py={[1, 2]}
>
<Flex
direction="column"
border={['solid 1px', 'initial']}
borderColor={['gray.100', 'inherit']}
borderRadius={['8px', 0]}
p={[4, 0]}
onClick={() => {
setState(idx)
if (!isDesktop) onOpenRentDetailDrawer()
}}
>
<Flex justifyContent="flex-start">
<Flex
direction="column"
maxW={['100%', 'initial']}
>
<Text
fontSize={['mdx', 'md']}
fontWeight={[500, 400]}
isTruncated
>
{p.data.url}
</Text>
<ProviderStatusLabel
status={p.status}
blocksLeft={p.blocksLeft}
></ProviderStatusLabel>
</Flex>
<Flex display="none">
<Text
fontSize="mdx"
fontWeight={500}
color="gray.064"
>
FILL_RATING
</Text>
<SoftStarIcon mt="3px" ml="3px" h={4} w={4} />
</Flex>
</Flex>
<Flex
display={['flex', 'none']}
justifyContent="flex-start"
>
<Flex
direction="column"
fontSize="base"
color="gray.064"
mt={4}
w="50%"
>
<Text>{t('Latency, sec')}</Text>
<Flex>
<Text color="gray.500" mr={1}>
{p.status === ProviderStatus.Error
? '—'
: (p.duration / 1000).toFixed(3)}
</Text>
<Text display="none">/ FILL_SLOTS</Text>
</Flex>
</Flex>
<Flex
direction="column"
fontSize="base"
color="gray.064"
mt={4}
w="50%"
>
<Text>Price</Text>
<Flex>
<Text color="gray.500">
{GetProviderPrice(
p.data,
identity?.state,
identity?.age
)}{' '}
iDNA
</Text>
</Flex>
</Flex>
</Flex>
</Flex>
</Td>
<Td display={['none', 'table-cell']}>
<Link
target="_blank"
rel="noreferrer"
color="brandBlue.100"
href={`https://t.me/${p.data.ownerName}`}
>
{p.data.ownerName}
</Link>
</Td>
<Td display={['none', 'table-cell']}>
{p.data.location}
</Td>
<Td display={['none', 'table-cell']}>
{p.status === ProviderStatus.Error
? '—'
: (p.duration / 1000).toFixed(3)}
</Td>
<Td display={['none', 'table-cell']} textAlign="right">
{p.slots}
</Td>
<Td display={['none', 'table-cell']} textAlign="right">
{GetProviderPrice(
p.data,
identity?.state,
identity?.age
)}{' '}
iDNA
</Td>
</Tr>
))}
</Tbody>
</Table>
</Box>
</Box>
<Stack
display={['none', 'flex']}
isInline
spacing={2}
justify="flex-end"
bg="white"
borderTop="1px"
borderTopColor="gray.100"
px={4}
py={3}
h={14}
position="fixed"
bottom={0}
left={0}
right={0}
>
<SecondaryButton onClick={router.back}>Cancel</SecondaryButton>
<PrimaryButton onClick={buySharedNodeDisclosure.onOpen}>
{t('Continue')}
</PrimaryButton>
</Stack>
</Page>
{selectedProvider && identity && (
<ProviderInfoDrawer
p={selectedProvider}
identity={identity}
isOpen={isOpenRentDetailDrawer}
onClose={onCloseRentDetailDrawer}
onSubmit={buySharedNodeDisclosure.onOpen}
/>
)}
<BuySharedNodeForm
{...buySharedNodeDisclosure}
providerId={selectedProvider && selectedProvider.id}
url={selectedProvider && selectedProvider.data.url}
from={coinbase}
amount={
selectedProvider &&
GetProviderPrice(
selectedProvider.data,
identity?.state,
identity?.age
)
}
to={selectedProvider && selectedProvider.data.address}
/>
</Layout>
)
}
Example #16
Source File: List.js From web-client with Apache License 2.0 | 4 votes |
UsersList = () => {
const navigate = useNavigate();
const loggedInUser = Auth.getLoggedInUser();
const [users, updateUsers] = useFetch("/users");
const deleteUser = useDelete("/users/", updateUsers);
const handleCreate = () => {
navigate("/users/create");
};
const [selectedUsers, setSelectedUsers] = useState([]);
const onTaskCheckboxChange = (ev) => {
const target = ev.target;
const targetUserId = parseInt(target.value);
if (target.checked) {
setSelectedUsers([...selectedUsers, targetUserId]);
} else {
setSelectedUsers(
selectedUsers.filter(value => value !== targetUserId)
);
}
};
const handleBulkDelete = () => {
secureApiFetch(`/users`, {
method: "PATCH",
headers: {
"Bulk-Operation": "DELETE",
},
body: JSON.stringify(selectedUsers),
})
.then(updateUsers)
.then(() => {
setSelectedUsers([]);
actionCompletedToast("All selected users were deleted.");
})
.catch(err => console.error(err));
};
const handleDelete = (id) => {
deleteUser(id);
updateUsers();
};
return <>
<PageTitle value="Users" />
<div className="heading">
<Breadcrumb />
<ButtonGroup isAttached>
<CreateButton onClick={handleCreate}>
Create user
</CreateButton>
<RestrictedComponent roles={['administrator']}>
<DeleteButton onClick={handleBulkDelete} disabled={selectedUsers.length === 0}>
Delete selected
</DeleteButton>
</RestrictedComponent>
<Menu>
<EllipsisMenuButton />
<MenuList>
<ExportMenuItem entity="users" />
</MenuList>
</Menu>
</ButtonGroup>
</div>
<Title title="Users and roles" icon={<IconUserGroup />} />
<Table>
<Thead>
<Tr>
<Th style={{ width: "32px" }}> </Th>
<Th style={{ width: "64px" }}> </Th>
<Th>Full name</Th>
<Th>Username</Th>
<Th>Role</Th>
<Th>Active?</Th>
<Th>2FA enabled?</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{null === users && <LoadingTableRow numColumns={8} />}
{null !== users && 0 === users.length && <NoResultsTableRow numColumns={8} />}
{null !== users && 0 !== users.length && users.map((user, index) => (
<Tr key={index}>
<Td>
<input
type="checkbox"
value={user.id}
onChange={onTaskCheckboxChange}
checked={selectedUsers.includes(user.id)}
/>
</Td>
<Td>
<UserAvatar email={user.email} />
</Td>
<Td>
<Link to={`/users/${user.id}`}>
{user.full_name}
</Link>
</Td>
<Td>
<UserLink userId={user.id}>
{user.username}
</UserLink>
</Td>
<Td>
<UserRoleBadge role={user.role} />
</Td>
<Td><BooleanText value={user.active} /></Td>
<Td><BooleanText value={user.mfa_enabled} /></Td>
<Td textAlign="right">
<LinkButton href={`/users/${user.id}/edit`}>
Edit
</LinkButton>
<DeleteIconButton
onClick={() => handleDelete(user.id)}
disabled={
parseInt(user.id) ===
loggedInUser.id
? "disabled"
: ""
}
/>
</Td>
</Tr>
))}
</Tbody>
</Table>
</>
}
Example #17
Source File: Profile.js From DAOInsure with MIT License | 4 votes |
function Profile() {
const web3Context = useContext(Web3Context);
const {
signerAddress,
userDaoTokenBalance,
fetchProposals,
fetchVotedProposals,
proposalsArray,
votedProposalsArray,
} = web3Context;
const [daoTokenBalance, setDaoTokenBalance] = useState(0);
const [stable, setStable] = useState(false);
useEffect(() => {
setInterval(async () => {
setDaoTokenBalance(await userDaoTokenBalance());
}, 10000);
}, []);
useEffect(() => {
fetchProposals();
fetchVotedProposals();
}, [stable]);
function con() {
console.log(proposalsArray);
}
return (
<VStack
alignItems='flex-start'
height='calc(100vh - 64px)'
px='250px'
py='20px'
width='100%'>
<HStack width='100%' alignItems='flex-start'>
<Box
borderWidth='2px'
borderRadius='full'
borderColor='whatsapp.500'
padding='2px'>
<Avatar
size='md'
icon={
<Jazzicon
diameter='48'
address={`${signerAddress}`}
/>
}
/>
</Box>
<VStack alignItems='flex-start'>
<Heading fontSize='20px'>{signerAddress}</Heading>
<Tag>10DAIx / month</Tag>
</VStack>
<Spacer />
<VStack>
<Tag>INSURE Tokens : {daoTokenBalance}</Tag>
</VStack>
</HStack>
<Grid
width='100%'
mt='30px !important'
templateColumns='3fr 2fr'
gridGap={5}
alignItems='flex-start'>
<Tabs
colorScheme='whatsapp'
variant='soft-rounded'
width='100%'>
<TabList>
<Tab onClick={con}>
Claims{" "}
<Tag ml={2} borderRadius='20px'>
{proposalsArray.length}
</Tag>
</Tab>
<Tab>
Voted For
<Tag ml={2} borderRadius='20px'>
{votedProposalsArray.length}
</Tag>
</Tab>
</TabList>
<TabPanels>
<TabPanel mt={3} padding={0}>
<Card cardTitle='Claims'>
<Table>
<Tbody>
{proposalsArray.map(function (
element,
id
) {
return (
<Tr key={id}>
<Th>
{" "}
{element[0].toNumber()}{" "}
</Th>
<Th>{element[2]}</Th>
<Th>
{element[7] ? (
<span>
{" "}
Passed{" "}
</span>
) : (
<span>
{" "}
Failed{" "}
</span>
)}
</Th>
</Tr>
);
})}
</Tbody>
</Table>
</Card>
</TabPanel>
<TabPanel mt={3} padding={0}>
<Card cardTitle='Claims'>
<Table>
<Tbody>
{votedProposalsArray.map(function (
element,
id
) {
return (
<Tr key={id}>
<Th>
{" "}
{element[0].toNumber()}{" "}
</Th>
<Th>{element[2]}</Th>
<Th>
{element[7] ? (
<span>
{" "}
Passed{" "}
</span>
) : (
<span>
{" "}
Failed{" "}
</span>
)}
</Th>
</Tr>
);
})}
</Tbody>
</Table>
</Card>
</TabPanel>
</TabPanels>
</Tabs>
</Grid>
</VStack>
);
}
Example #18
Source File: Targets.js From web-client with Apache License 2.0 | 4 votes |
ProjectTargets = ({ project }) => {
const query = useQuery();
const urlPageNumber = query.get('page') !== null ? parseInt(query.get('page')) : 1;
const [pageNumber, setPageNumber] = useState(urlPageNumber);
const [numberPages, setNumberPages] = useState(1);
const [targets, setTargets] = useState([]);
const { isOpen: isAddTargetDialogOpen, onOpen: openAddTargetDialog, onClose: closeAddTargetDialog } = useDisclosure();
const onDeleteButtonClick = (ev, targetId) => {
ev.preventDefault();
secureApiFetch(`/targets/${targetId}`, { method: 'DELETE' })
.then(() => {
reloadTargets();
})
}
const onTargetFormSaved = () => {
reloadTargets();
closeAddTargetDialog();
}
const reloadTargets = useCallback(() => {
setTargets([]);
secureApiFetch(`/targets?projectId=${project.id}&page=${pageNumber - 1}`, { method: 'GET' })
.then(resp => {
if (resp.headers.has('X-Page-Count')) {
setNumberPages(resp.headers.get('X-Page-Count'))
}
return resp.json()
})
.then(data => {
setTargets(data);
});
}, [pageNumber, project]);
const onPrevPageClick = () => {
setPageNumber(pageNumber - 1);
}
const onNextPageClick = () => {
setPageNumber(pageNumber + 1);
}
useEffect(() => {
reloadTargets()
}, [reloadTargets])
return <section>
<h4>
<IconServer />Targets
<RestrictedComponent roles={['administrator', 'superuser', 'user']}>
<ButtonGroup>
<TargetModalDialog project={project} isOpen={isAddTargetDialogOpen} onSubmit={onTargetFormSaved} onCancel={closeAddTargetDialog} />
<CreateButton onClick={openAddTargetDialog}>Add target...</CreateButton>
</ButtonGroup>
</RestrictedComponent>
</h4>
{!targets ? <Loading /> :
<>
{numberPages > 1 && <Center>
<Pagination page={pageNumber - 1} total={numberPages} handlePrev={onPrevPageClick} handleNext={onNextPageClick} />
</Center>}
<Table>
<Thead>
<Tr>
<Th>Name</Th>
<Th>Sub-target</Th>
<Th>Kind</Th>
<Th>Vulnerable?</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{targets.length === 0 && <NoResultsTableRow numColumns={4} />}
{targets.map((target, index) =>
<Tr key={index}>
<Td>
{target.parent_id === null &&
<HStack>
<Link to={`/targets/${target.id}`}><TargetBadge name={target.name} /></Link>
</HStack>
}
{target.parent_id !== null &&
<>{target.parent_name ?? '-'}</>
}
</Td>
<Td>{target.parent_id !== null ?
<>
<Link to={`/targets/${target.id}`}><TargetBadge name={target.name} /></Link>
</> : '-'}</Td>
<Td>{target.kind} <Tags values={target.tags} /></Td>
<Td>{target.num_vulnerabilities > 0 ? `Yes (${target.num_vulnerabilities} vulnerabilities found)` : "No"}</Td>
<Td>
<RestrictedComponent roles={['administrator', 'superuser', 'user']}>
<DeleteIconButton onClick={ev => onDeleteButtonClick(ev, target.id)} />
</RestrictedComponent>
</Td>
</Tr>
)}
</Tbody>
</Table>
</>
}
</section>
}
Example #19
Source File: validation-report.js From idena-web with MIT License | 4 votes |
export default function ValidationReport() {
const {t, i18n} = useTranslation()
const {colors} = useTheme()
const epoch = useEpoch()
const [identity] = useIdentity()
const isMobile = useMobile()
const {address, state, isValidated} = identity
const {
prevState,
lastValidationScore,
totalScore,
earnings,
earningsScore,
validationReward,
missedValidationReward,
invitationReward,
missedInvitationReward,
flipReward,
missedFlipReward,
flipReportReward,
missedFlipReportReward,
totalMissedReward,
validationResult,
stakingReward,
missedStakingReward,
candidateReward,
missedCandidateReward,
isLoading,
} = useValidationReportSummary()
const {
short: {score: shortScore, ...shortResults},
long: {score: longScore, ...longResults},
} = lastValidationScore
const toDna = toLocaleDna(i18n.language, {maximumFractionDigits: 3})
const maybeDna = amount =>
!amount || Number.isNaN(amount)
? '–'
: amount.toLocaleString(i18n.language, {maximumFractionDigits: 3})
const epochNumber = epoch?.epoch
return (
<Layout>
<Page as={Stack} spacing={6}>
<Flex
justify="space-between"
align="center"
w="full"
alignItems="center"
>
<AngleArrowBackIcon
stroke="#578FFF"
position="absolute"
left={4}
top={4}
h="28px"
w="28px"
onClick={() => router.back()}
display={['initial', 'none']}
/>
<PageTitleNew mb={0} mt={[-2, 0]}>
{t('Epoch #{{epochNumber}} validation report', {epochNumber})}
</PageTitleNew>
<CloseButton
display={['none', 'initial']}
onClick={() => router.push('/home')}
/>
</Flex>
<Stack spacing={6} w="full">
<Box>
<Skeleton isLoaded={!isLoading} alignSelf="start">
{isValidated ? (
<SuccessAlert>
{validationResult === ValidationResult.Success &&
t('Successfully validated')}
{validationResult === ValidationResult.Penalty &&
t('Validated')}
</SuccessAlert>
) : (
<ErrorAlert>{t('Validation failed')}</ErrorAlert>
)}
</Skeleton>
</Box>
<Box py={2} display={['none', 'block']}>
<UserCard identity={{address, state}} />
</Box>
<Stack isInline={!isMobile} spacing={[4, 10]}>
<ValidationReportBlockOverview>
<Stack spacing={[6, 10]}>
<Box>
<ValidationReportGauge>
<ValidationReportGaugeBox>
{isLoading ? (
<ValidationReportGaugeBar color={colors.gray['100']} />
) : isValidated ? (
<ValidationReportGaugeBar
value={totalScore * 100}
color={
totalScore <= 0.75
? colors.red['500']
: totalScore <= 0.9
? colors.orange['500']
: colors.green['500']
}
bg="white"
/>
) : (
<ValidationReportGaugeBar
value={shortScore * 100 || 2}
color={colors.red['500']}
bg="white"
/>
)}
<ValidationReportGaugeIcon
icon={<TimerIcon />}
display={['none', 'initial']}
/>
</ValidationReportGaugeBox>
<ValidationReportGaugeStat>
<Skeleton isLoaded={!isLoading} w="auto">
{isValidated ? (
<ValidationReportGaugeStatValue>
{toPercent(totalScore)}
</ValidationReportGaugeStatValue>
) : (
<ValidationReportGaugeStatValue color="red.500">
{t('Failed')}
</ValidationReportGaugeStatValue>
)}
</Skeleton>
<Skeleton isLoaded={!isLoading} w="auto">
<ValidationReportGaugeStatLabel>
{isValidated && t('Total score')}
{validationResult ===
ValidationResult.LateSubmission &&
t('Late submission')}
{validationResult ===
ValidationResult.MissedValidation &&
t('Missed validation')}
{validationResult === ValidationResult.WrongAnswers &&
t('Wrong answers')}
</ValidationReportGaugeStatLabel>
</Skeleton>
</ValidationReportGaugeStat>
</ValidationReportGauge>
</Box>
<Stack spacing={[2, 4]} isInline={!isMobile}>
<Flex justify="space-between">
<Skeleton isLoaded={!isLoading}>
<ValidationReportStat
label={t('Short session')}
value={
[
ValidationResult.MissedValidation,
ValidationResult.LateSubmission,
].includes(validationResult)
? '—'
: t('{{score}} ({{point}} out of {{flipsCount}})', {
score: toPercent(shortScore),
point: shortResults.point,
flipsCount: shortResults.flipsCount,
})
}
/>
</Skeleton>
</Flex>
<Divider
orientation="horizontal"
display={['initial', 'none']}
/>
<Flex justify="space-between">
<Skeleton isLoaded={!isLoading}>
<ValidationReportStat
label={t('Long session')}
value={
validationResult === ValidationResult.MissedValidation
? '—'
: t('{{score}} ({{point}} out of {{flipsCount}})', {
score: toPercent(longScore),
point: longResults.point,
flipsCount: longResults.flipsCount,
})
}
/>
</Skeleton>
</Flex>
</Stack>
</Stack>
</ValidationReportBlockOverview>
<ValidationReportBlockOverview>
<Stack spacing={[6, 10]}>
<Box>
<ValidationReportGauge>
<ValidationReportGaugeBox>
{isLoading ? (
<ValidationReportGaugeBar color={colors.gray['100']} />
) : isValidated ? (
<ValidationReportGaugeBar
value={earningsScore * 100 || 2}
color={
// eslint-disable-next-line no-nested-ternary
earningsScore <= 0.5
? colors.red['500']
: earningsScore <= 0.75
? colors.orange['500']
: colors.green['500']
}
bg="white"
/>
) : (
<ValidationReportGaugeBar
value={2}
color={colors.red['500']}
bg="white"
/>
)}
<ValidationReportGaugeIcon
icon={<SendOutIcon />}
display={['none', 'initial']}
/>
</ValidationReportGaugeBox>
<ValidationReportGaugeStat>
<Skeleton isLoaded={!isLoading} w="auto">
{validationResult === ValidationResult.Success ? (
<ValidationReportGaugeStatValue>
{toDna(earnings)}
</ValidationReportGaugeStatValue>
) : (
<ValidationReportGaugeStatValue color="red.500">
{toDna(totalMissedReward)}
</ValidationReportGaugeStatValue>
)}
</Skeleton>
<ValidationReportGaugeStatLabel>
{t('Earnings')}
</ValidationReportGaugeStatLabel>
</ValidationReportGaugeStat>
</ValidationReportGauge>
</Box>
<Flex justify="space-between" flexWrap="wrap">
<Flex mr={4} mb={[0, 4]}>
<Skeleton isLoaded={!isLoading}>
<ValidationReportStat
label={t('Missed invitation earnings')}
value={toDna(missedInvitationReward)}
/>
</Skeleton>
</Flex>
<Divider
orientation="horizontal"
display={['initial', 'none']}
my={2}
/>
<Flex mr={4} mb={[0, 4]}>
<Skeleton isLoaded={!isLoading}>
<ValidationReportStat
label={t('Missed reporting earnings')}
value={toDna(missedFlipReportReward)}
/>
</Skeleton>
</Flex>
<Divider
orientation="horizontal"
display={['initial', 'none']}
my={2}
/>
<Flex mr={4} mb={[0, 4]}>
<Skeleton isLoaded={!isLoading}>
<ValidationReportStat
label={t('Missed flip earnings')}
value={toDna(missedFlipReward)}
/>
</Skeleton>
</Flex>
</Flex>
</Stack>
</ValidationReportBlockOverview>
</Stack>
<Stack spacing={[0, 5]}>
<Box mb={2}>
<Heading color="brandGray.500" fontSize="lg" fontWeight={500}>
{t('Earnings summary')}
</Heading>
<ExternalLink
href={`https://scan.idena.io/identity/${address}/epoch/${
epoch?.epoch
}/${isValidated ? 'rewards' : 'validation'}`}
>
{t('See the full report in blockchain explorer')}
</ExternalLink>
</Box>
<Table fontWeight={500}>
<Thead display={['none', 'table-header-group']}>
<Tr>
<ValidationReportTh>
{t('Category')}
<ValidationReportThCorner borderLeftRadius="md" />
</ValidationReportTh>
<ValidationReportTh>
{t('Earned, iDNA')}
<ValidationReportThCorner />
</ValidationReportTh>
<ValidationReportTh>
{t('Missed, iDNA')}
<ValidationReportThCorner />
</ValidationReportTh>
<ValidationReportTh style={{width: '260px'}}>
{t('How to get maximum reward')}
<ValidationReportThCorner borderRightRadius="md" />
</ValidationReportTh>
</Tr>
</Thead>
<Tbody>
{stakingReward === 0 && candidateReward === 0 ? (
<>
<Tr>
<ValidationReportColumn>
<ValidationReportCategoryLabel
isFirst
label={t('Validation')}
description={
isMobile
? t('Category')
: t('Rewards for the successfull validation')
}
info={t('Rewards for the successfull validation')}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={maybeDna(validationReward)}
description={isMobile ? t('Earned') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={
<Text
color={
missedValidationReward > 0 ? 'red.500' : ''
}
>
{maybeDna(missedValidationReward)}
</Text>
}
description={isMobile ? t('Missed') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn display={['none', 'table-cell']}>
<TableValidationDesc
t={t}
validationResult={validationResult}
missedValidationReward={missedValidationReward}
/>
</ValidationReportColumn>
</Tr>
<TableHiddenDescRow>
<TableValidationDesc
t={t}
validationResult={validationResult}
missedValidationReward={missedValidationReward}
/>
</TableHiddenDescRow>
</>
) : (
<>
<Tr>
<ValidationReportColumn>
<ValidationReportCategoryLabel
isFirst
label={t('Staking')}
description={t('Quadratic staking rewards')}
info={t('Quadratic staking rewards')}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={maybeDna(stakingReward)}
description={isMobile ? t('Earned') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={
<Text
color={missedStakingReward > 0 ? 'red.500' : ''}
>
{maybeDna(missedStakingReward)}
</Text>
}
description={isMobile ? t('Missed') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn display={['none', 'table-cell']}>
<TextLink href="/home?replenishStake">
{t('Add stake')}
<ChevronRightIcon />
</TextLink>
</ValidationReportColumn>
</Tr>
<TableHiddenDescRow>
<TextLink href="/home">
{t('Add stake')}
<ChevronRightIcon />
</TextLink>
</TableHiddenDescRow>
{state === IdentityStatus.Newbie &&
prevState === IdentityStatus.Candidate && (
<>
<Tr>
<ValidationReportColumn>
<ValidationReportCategoryLabel
isFirst
label={t('Validation')}
description={
isMobile
? t('Category')
: t(
'Rewards for the 1st successful validation'
)
}
info={t(
'Rewards for the 1st successful validation'
)}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={maybeDna(candidateReward)}
description={isMobile ? t('Earned') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={
<Text
color={
missedCandidateReward > 0 ? 'red.500' : ''
}
>
{maybeDna(missedCandidateReward)}
</Text>
}
description={isMobile ? t('Missed') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn
display={['none', 'table-cell']}
>
<TableValidationDesc
t={t}
validationResult={validationResult}
missedValidationReward={missedCandidateReward}
/>
</ValidationReportColumn>
</Tr>
<TableHiddenDescRow>
<TableValidationDesc
t={t}
validationResult={validationResult}
missedValidationReward={missedCandidateReward}
/>
</TableHiddenDescRow>
</>
)}
</>
)}
<Tr>
<ValidationReportColumn>
<ValidationReportCategoryLabel
isFirst
label={t('Flips')}
description={
isMobile
? t('Category')
: t('Rewards for submitted and qualified flips')
}
info={t('Rewards for submitted and qualified flips')}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={maybeDna(flipReward)}
description={isMobile ? t('Earned') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={
<Text color={missedFlipReward > 0 ? 'red.500' : ''}>
{maybeDna(missedFlipReward)}
</Text>
}
description={isMobile ? t('Missed') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn display={['none', 'table-cell']}>
<TableFlipsDesc
t={t}
validationResult={validationResult}
missedFlipReward={missedFlipReward}
flipReward={flipReward}
/>
</ValidationReportColumn>
</Tr>
<TableHiddenDescRow>
<TableFlipsDesc
t={t}
validationResult={validationResult}
missedFlipReward={missedFlipReward}
flipReward={flipReward}
/>
</TableHiddenDescRow>
<Tr>
<ValidationReportColumn>
<ValidationReportCategoryLabel
isFirst
label={t('Invitations')}
description={
isMobile
? t('Category')
: t('Rewards for invitee validation')
}
info={t('Rewards for invitee validation')}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={maybeDna(invitationReward)}
description={isMobile ? t('Earned') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={
<Text
color={missedInvitationReward > 0 ? 'red.500' : ''}
>
{maybeDna(missedInvitationReward)}
</Text>
}
description={isMobile ? t('Missed') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn display={['none', 'table-cell']}>
<TableInvitationsDesc
t={t}
validationResult={validationResult}
missedInvitationReward={missedInvitationReward}
invitationReward={invitationReward}
/>
</ValidationReportColumn>
</Tr>
<TableHiddenDescRow>
<TableInvitationsDesc
t={t}
validationResult={validationResult}
missedInvitationReward={missedInvitationReward}
invitationReward={invitationReward}
/>
</TableHiddenDescRow>
<Tr>
<ValidationReportColumn>
<ValidationReportCategoryLabel
isFirst
label={t('Flip reports')}
description={
isMobile
? t('Category')
: t('Rewards for reporting bad flips')
}
info={t('Rewards for reporting bad flips')}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={maybeDna(flipReportReward)}
description={isMobile ? t('Earned') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn>
<ValidationReportCategoryLabel
label={
<Text
color={missedFlipReportReward > 0 ? 'red.500' : ''}
>
{maybeDna(missedFlipReportReward)}
</Text>
}
description={isMobile ? t('Missed') : ''}
/>
</ValidationReportColumn>
<ValidationReportColumn display={['none', 'table-cell']}>
<TableFlipReportsDesc
t={t}
validationResult={validationResult}
missedFlipReportReward={missedFlipReportReward}
flipReportReward={flipReportReward}
/>
</ValidationReportColumn>
</Tr>
<TableHiddenDescRow>
<TableFlipReportsDesc
t={t}
validationResult={validationResult}
missedFlipReportReward={missedFlipReportReward}
flipReportReward={flipReportReward}
/>
</TableHiddenDescRow>
</Tbody>
</Table>
</Stack>
</Stack>
</Page>
</Layout>
)
}
Example #20
Source File: Membership.js From web-client with Apache License 2.0 | 4 votes |
ProjectMembership = () => {
const { projectId } = useParams();
const [users] = useFetch(`/users`)
const [members, updateMembers] = useFetch(`/projects/${projectId}/users`)
const [savedProject] = useFetch(`/projects/${projectId}`);
const [availableUsers, setAvailableUsers] = useState([]);
const handleOnClick = ev => {
ev.preventDefault();
const userId = document.getElementById('userId').value;
const userData = { userId: userId };
secureApiFetch(`/projects/${projectId}/users`, {
method: 'POST',
body: JSON.stringify(userData)
}).then(() => {
updateMembers()
})
}
const handleDelete = (member) => {
secureApiFetch(`/projects/${projectId}/users/${member.membership_id}`, {
method: 'DELETE'
}).then(() => {
updateMembers()
})
}
useEffect(() => {
if (members && users && users.length > 0) {
const memberIds = members.reduce((list, user) => [...list, user.id], []);
setAvailableUsers(users.filter(user => !memberIds.includes(user.id)));
}
}, [members, users]);
return <div>
<PageTitle value="Project membership" />
<div className="heading">
<Breadcrumb>
<Link to="/projects">Projects</Link>
{savedProject && <Link to={`/projects/${savedProject.id}`}>{savedProject.name}</Link>}
</Breadcrumb>
</div>
<Title title='Members' />
{availableUsers.length > 0 ?
<form>
<label>
Select user
<Select id="userId">
{availableUsers && availableUsers.map((user, index) =>
<option key={index} value={user.id}>{user.full_name}</option>
)}
</Select>
</label>
<PrimaryButton onClick={handleOnClick} leftIcon={<IconPlus />}>Add as member</PrimaryButton>
</form> :
<Alert status="info">
<AlertIcon />
All users have been added to the project.
</Alert>
}
<Table>
<Thead>
<Tr>
<Th style={{ width: '80px' }}> </Th>
<Th>Name</Th>
<Th>Role</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{null === members &&
<LoadingTableRow numColumns={4} />}
{null !== members && 0 === members.length &&
<NoResultsTableRow numColumns={4} />}
{members && members.map((member, index) =>
<Tr key={index}>
<Td><UserAvatar email={member.email} /></Td>
<Td><UserLink userId={member.id}>{member.full_name}</UserLink></Td>
<Td><UserRoleBadge role={member.role} /></Td>
<Td textAlign="right">
<DeleteIconButton onClick={() => handleDelete(member)} />
</Td>
</Tr>
)
}
</Tbody>
</Table>
</div>
}
Example #21
Source File: components.js From idena-web with MIT License | 4 votes |
export function WalletTransactions({address}) {
const LIMIT = 10
const {t, i18n} = useTranslation()
const toNumber = toLocaleNumber(i18n.language, {maximumFractionDigits: 4})
const fetchTxs = ({pageParam = null}) =>
getTxs(address, LIMIT, pageParam).then(result => {
if (!result) {
return {result: []}
}
const newResult = result.map(tx => {
const fromWallet =
lowerCase(address) === lowerCase(tx.from) ? address : null
const toWallet =
lowerCase(address) === lowerCase(tx.to) ? address : null
const direction = fromWallet ? t('Sent') : t('Received')
const typeName = tx.type === 'SendTx' ? direction : transactionType(tx)
const sourceWallet = fromWallet || toWallet
const signAmount = fromWallet ? -tx.amount : `+${tx.amount}`
const counterParty = fromWallet ? tx.to : tx.from
const counterPartyWallet = fromWallet ? toWallet : fromWallet
const isMining = !tx.timestamp
const nextTx = {
...tx,
typeName,
wallet: sourceWallet,
direction,
signAmount,
counterParty,
counterPartyWallet,
isMining,
}
return nextTx
})
return {result: newResult, continuationToken: result.continuationToken}
})
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
status,
} = useInfiniteQuery(['transactions', address], fetchTxs, {
getNextPageParam: lastPage => lastPage?.continuationToken,
refetchInterval: 10 * 1000,
})
const isLoading = status === 'loading'
return (
<div>
<Table
sx={{
'&': {
tableLayout: 'fixed',
},
tr: {
'&:last-of-type': {
td: {borderBottomWidth: 0},
},
},
}}
>
<Thead display={['none', 'table-header-group']}>
<Tr>
<RoundedTh isLeft>{t('Transaction')}</RoundedTh>
<RoundedTh>{t('Address')}</RoundedTh>
<RoundedTh textAlign="right">{t('Amount, iDNA')}</RoundedTh>
<RoundedTh textAlign="right">{t('Fee, iDNA')}</RoundedTh>
<RoundedTh>{t('Date')}</RoundedTh>
<RoundedTh isRight>{t('Blockchain transaction ID')}</RoundedTh>
</Tr>
</Thead>
<Tbody>
{!isLoading &&
data &&
data.pages.map((group, i) => (
<React.Fragment key={i}>
{group.result.map((tx, k) => (
<Tr key={i + k}>
<TransactionsTd>
<RowStatus
isMining={tx.isMining}
direction={tx.direction}
type={tx.typeName}
walletName="Main"
tx={tx}
/>
</TransactionsTd>
<TransactionsTd display={['none', 'table-cell']}>
{(!tx.to && '\u2013') || (
<Flex align="center">
<Avatar
address={lowerCase(tx.counterParty)}
size={8}
/>
<Box ml={3}>
<div>
{tx.direction === 'Sent' ? t('To') : t('From')}{' '}
{tx.counterPartyWallet
? `${t('wallet')} Main`
: t('address')}
</div>
<TableHint>
<Text isTruncated w="130px">
{tx.counterParty}
</Text>
</TableHint>
</Box>
</Flex>
)}
</TransactionsTd>
<TransactionsTd
display={['none', 'table-cell']}
textAlign="right"
>
<Box color={tx.signAmount < 0 ? 'red.500' : 'gray.500'}>
{(tx.type === 'kill' && t('See in Explorer...')) ||
(tx.amount === '0'
? '\u2013'
: toNumber(tx.signAmount))}
</Box>
</TransactionsTd>
<TransactionsTd
display={['none', 'table-cell']}
textAlign="right"
>
{(!tx.isMining &&
(tx.fee === '0' ? '\u2013' : toNumber(tx.fee))) || (
<div>
<div> {tx.maxFee} </div>
<TableHint>{t('Fee limit')}</TableHint>
</div>
)}
</TransactionsTd>
<TransactionsTd display={['none', 'table-cell']}>
{!tx.timestamp
? '\u2013'
: new Date(tx.timestamp).toLocaleString()}
</TransactionsTd>
<TransactionsTd display={['none', 'table-cell']}>
<div>
<div>
{tx.isMining ? t('Mining...') : t('Confirmed')}
</div>
<TableHint>
<Text isTruncated w="130px">
{tx.hash}
</Text>
</TableHint>
</div>
</TransactionsTd>
</Tr>
))}
</React.Fragment>
))}
</Tbody>
</Table>
{isLoading && (
<Stack spacing={2} mt={2}>
{new Array(10).fill(0).map((_, i) => (
<Skeleton key={i} height={10} w="full"></Skeleton>
))}
</Stack>
)}
{!isLoading && hasNextPage && (
<Flex justify="center" mt={2}>
<FlatButton
mb={2.5}
onClick={() => fetchNextPage()}
disabled={isFetchingNextPage}
>
{isFetchingNextPage ? t('Loading more...') : t('Load More')}
</FlatButton>
</Flex>
)}
{!isLoading && data?.pages && data.pages[0].result?.length === 0 && (
<Box color="muted" textAlign="center" lineHeight="40vh">
{t(`You don't have any transactions yet`)}
</Box>
)}
</div>
)
}
Example #22
Source File: ChallengeReviewRow.jsx From scaffold-directory with MIT License | 4 votes |
export default function ChallengeReviewRow({ challenge, isLoading, approveClick, rejectClick, userProvider }) {
const [comment, setComment] = useState(challenge.reviewComment ?? "");
const [testPassed, setTestPassed] = useState(null);
const [isRunningTests, setIsRunningTests] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const address = useUserAddress(userProvider);
if (!challengeInfo[challenge.id]) {
return null;
}
// We asume that rejected challenges will always have review Comments.
const isAutograded = challenge.autograding;
// ToDo. Use the stored events.
const isResubmitted = !isAutograded && !!challenge.reviewComment;
const runTests = async () => {
try {
console.log("Testing challenge with the auto-grader");
setIsRunningTests(true);
setTestPassed(null);
const result = await runAutograderTest(challenge.id, challenge.contractUrl, address);
const resultData = result.data;
console.log("Testing results", resultData);
setTestPassed(resultData.success);
setComment(resultData.feedback ?? resultData.error);
} catch (e) {
console.log("Error calling the auto-grader", e);
} finally {
setIsRunningTests(false);
}
};
const challengeReviewDisplay = (
<Link as={RouteLink} to={`/challenge/${challenge.id}`}>
{challengeInfo[challenge.id].label}
{isResubmitted && (
<>
<br />
<Text fontSize="xs">(Resubmitted)</Text>
</>
)}
{isAutograded && (
<>
<br />
<Text fontSize="xs" color="orange.500">
(Autograded)
</Text>
</>
)}
</Link>
);
const submittedMoment = moment(challenge.submittedTimestamp);
const reviewRow = (
<>
<Td>
<Link as={RouteLink} to={`/builders/${challenge.userAddress}`} pos="relative">
<Address address={challenge.userAddress} w="12.5" fontSize="16" />
</Link>
</Td>
<Td>{challengeReviewDisplay}</Td>
<Td>
<DateWithTooltip timestamp={challenge.submittedTimestamp} />
</Td>
</>
);
return (
<Tr>
{reviewRow}
<Td>
<Button type="button" colorScheme="blue" disabled={isLoading} className="danger" onClick={onOpen} size="xs">
Review
</Button>
</Td>
<Modal isOpen={isOpen} onClose={onClose} size="xl">
<ModalOverlay />
<ModalContent maxW="56rem">
<ModalHeader>Review Challenge</ModalHeader>
<ModalCloseButton />
<Table mb={4}>
<Thead>
<Tr>
<Th>Builder</Th>
<Th>Challenge & Links</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td>
<Link as={RouteLink} to={`/builders/${challenge.userAddress}`} pos="relative">
<Address address={challenge.userAddress} w="12.5" fontSize="16" />
</Link>
</Td>
<Td>
{challengeReviewDisplay}
<UnorderedList>
<ListItem>
<Link
// Legacy branchUrl
href={challenge.contractUrl || challenge.branchUrl}
color="teal.500"
target="_blank"
rel="noopener noreferrer"
>
Contract
</Link>
</ListItem>
<ListItem>
<Link href={challenge.deployedUrl} color="teal.500" target="_blank" rel="noopener noreferrer">
Demo
</Link>
</ListItem>
<ListItem>
Submitted{" "}
<Tooltip label={submittedMoment.format("YYYY-MM-DD, HH:mm")}>
<chakra.span cursor="pointer">{submittedMoment.fromNow()}</chakra.span>
</Tooltip>
</ListItem>
<ListItem listStyleType="none" mt={2}>
<Flex align="center">
<Button onClick={runTests} isLoading={isRunningTests} mr={2}>
Run tests
</Button>
{isBoolean(testPassed) && (
<Badge colorScheme={testPassed ? "green" : "red"}>
{testPassed ? "Accepted" : "Rejected"}
</Badge>
)}
</Flex>
</ListItem>
</UnorderedList>
</Td>
</Tr>
</Tbody>
</Table>
<ModalBody px={6} pb={0}>
<Tabs variant="enclosed-colored">
<TabList>
<Tab>Write</Tab>
<Tab>Preview</Tab>
</TabList>
<TabPanels align="left">
<TabPanel p={0}>
<Textarea
onChange={e => {
const value = e.target.value;
setComment(value);
}}
placeholder="Comment"
style={{ marginBottom: 10 }}
rows={10}
value={comment}
borderTopRadius={0}
/>
</TabPanel>
<TabPanel>
<ReactMarkdown components={ChakraUIRenderer(chakraMarkdownComponents)}>{comment}</ReactMarkdown>
</TabPanel>
</TabPanels>
</Tabs>
</ModalBody>
<ModalFooter>
<Button
type="button"
colorScheme="red"
disabled={isLoading}
className="danger"
onClick={() => rejectClick(challenge.userAddress, challenge.id, comment)}
size="sm"
isFullWidth
>
Reject
</Button>
<Button
type="button"
colorScheme="green"
disabled={isLoading}
ml={3}
onClick={() => approveClick(challenge.userAddress, challenge.id, comment)}
size="sm"
isFullWidth
>
Approve
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Tr>
);
}
Example #23
Source File: Outputs.js From web-client with Apache License 2.0 | 4 votes |
CommandOutputs = ({ command }) => {
const [commandOutputs, updateCommandOutputs] = useFetch(`/attachments?parentType=command&parentId=${command.id}`)
const [modalVisible, setModalVisible] = useState(false);
const [content, setContent] = useState(null);
const onDeleteOutputClick = (ev, attachmentId) => {
ev.preventDefault();
secureApiFetch(`/attachments/${attachmentId}`, { method: 'DELETE' })
.then(() => {
actionCompletedToast("The output has been deleted.");
updateCommandOutputs();
})
.catch(err => console.error(err))
}
const onDownloadClick = (ev, attachmentId) => {
secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
.then(resp => {
const contentDispositionHeader = resp.headers.get('Content-Disposition');
const filenameRe = new RegExp(/filename="(.*)";/)
const filename = filenameRe.exec(contentDispositionHeader)[1]
return Promise.all([resp.blob(), filename]);
})
.then((values) => {
const blob = values[0];
const filename = values[1];
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
})
}
const onViewClick = (ev, attachmentId) => {
secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
.then(resp => {
const contentDispositionHeader = resp.headers.get('Content-Disposition');
const filenameRe = new RegExp(/filename="(.*)";/)
const filename = filenameRe.exec(contentDispositionHeader)[1]
return Promise.all([resp.blob(), filename]);
})
.then(async (values) => {
const blob = values[0];
setContent(await blob.text());
setModalVisible(true);
})
}
const onModalClose = () => {
setModalVisible(false);
}
return <>
<ModalDialog visible={modalVisible} title="Preview output" onModalClose={onModalClose} style={{ width: '80%', height: '80%', maxHeight: '80%' }}>
<Textarea style={{ width: '100%', height: '90%' }} defaultValue={content} readOnly>
</Textarea>
</ModalDialog>
<RestrictedComponent roles={['administrator', 'superuser', 'user']}>
<AttachmentsDropzone parentType={"command"} parentId={command.id} onUploadFinished={updateCommandOutputs} />
</RestrictedComponent>
<h4>
Command output list
</h4>
<Table>
<Thead>
<Tr>
<Th>Filename</Th>
<Th>Mimetype</Th>
<Th>File size</Th>
<Th>Upload date</Th>
<Th>Uploaded by</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{null === commandOutputs && <LoadingTableRow numColumns={6} />}
{null !== commandOutputs && commandOutputs.length === 0 && <NoResultsTableRow numColumns={6} />}
{null !== commandOutputs && commandOutputs.length !== 0 && commandOutputs.map((commandOutput, index) =>
<Tr key={index}>
<Td>{commandOutput.client_file_name}</Td>
<Td>{commandOutput.file_mimetype}</Td>
<Td><FileSizeSpan fileSize={commandOutput.file_size} /></Td>
<Td><RelativeDateFormatter date={commandOutput.insert_ts} /></Td>
<Td><UserLink userId={commandOutput.submitter_uid}>{commandOutput.submitter_name}</UserLink></Td>
<Td textAlign="right">
<ButtonGroup isAttached>
<SecondaryButton onClick={ev => onViewClick(ev, commandOutput.id)}>View</SecondaryButton>
<SecondaryButton onClick={ev => onDownloadClick(ev, commandOutput.id)}>Download</SecondaryButton>
<DeleteIconButton onClick={ev => onDeleteOutputClick(ev, commandOutput.id)} />
</ButtonGroup>
</Td>
</Tr>
)}
</Tbody>
</Table>
</>
}
Example #24
Source File: ActivityPage.js From DAOInsure with MIT License | 4 votes |
function ActivityPage() {
const [data, setData] = useState();
const [loadingData, setLoadingData] = useState();
useEffect(() => {
async function init() {
setLoadingData(true);
// querying superfluid subgraph to create pie diagram of flow towards DAO Contract
const response = await axios.post(
"https://api.thegraph.com/subgraphs/name/superfluid-finance/superfluid-mumbai",
{
query: `
{
flows(where:{ recipient: "0xb77963bfd55f5246068c09a2048fa3ab310e4a17" }) {
id
flowRate
lastUpdate
owner {
id
}
}
}
`,
}
);
let datas = [];
response.data.data.flows.map((flow) => {
let secondsElapsed =
Math.floor(Date.now() / 1000) - parseInt(flow.lastUpdate);
let outFlowed = web3.utils.fromWei(
web3.utils
.toBN(flow.flowRate)
.mul(web3.utils.toBN(secondsElapsed))
.toString(),
"ether"
);
let obj = {
id: flow.owner.id,
label: flow.owner.id,
value: outFlowed,
flowRate: web3.utils.toBN(flow.flowRate),
sumInWei: web3.utils
.toBN(flow.flowRate)
.mul(web3.utils.toBN(secondsElapsed)),
};
datas.push(obj);
});
setData(datas);
setLoadingData(false);
}
init();
}, [data]);
useEffect(() => {
if (data != undefined) {
setTimeout(() => {
for (let i = 0; i < data.length; i++) {
data[i].value = web3.utils
.fromWei(data[i].sumInWei.add(data[i].flowRate))
.toString();
data[i].sumInWei = data[i].sumInWei.add(data[i].flowRate);
}
setData(data);
}, 1000);
}
}, [data]);
return (
<Grid px='250px' gridGap='10px' py='20px'>
<Heading fontSize='24px' color='whatsapp.500'>
Members
</Heading>
<Box height='400px'>
{loadingData ? <Spinner /> : <MyResponsivePie data={data} />}
</Box>
<Table>
<Thead>
<Tr>
<Th>Address</Th>
<Th>outFlowed</Th>
</Tr>
</Thead>
<Tbody>
{data == undefined ? (
<Spinner />
) : (
<>
{data.map((data, index) => {
return (
<Tr>
<Td>
<GreenTag>{data.id}</GreenTag>
</Td>
<Td>{data.value}</Td>
</Tr>
);
})}
</>
)}
</Tbody>
</Table>
</Grid>
);
}
Example #25
Source File: AttachmentsTable.js From web-client with Apache License 2.0 | 4 votes |
AttachmentsTable = ({ attachments, reloadAttachments }) => {
const [modalVisible, setModalVisible] = useState(false);
const [content, setContent] = useState(null);
const onModalClose = () => {
setModalVisible(false);
}
const deleteAttachmentById = useDelete('/attachments/', reloadAttachments);
const onViewClick = (ev, attachmentId) => {
secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
.then(resp => {
const contentDispositionHeader = resp.headers.get('Content-Disposition');
const contentType = resp.headers.get('Content-Type');
const filenameRe = new RegExp(/filename="(.*)";/)
const filename = filenameRe.exec(contentDispositionHeader)[1]
return Promise.all([contentType, filename, resp.blob()]);
})
.then(async (values) => {
const [contentType, , blob] = values;
if (contentType.indexOf('image/') !== -1) {
setContent(<img src={await URL.createObjectURL(blob)} alt="" />);
// @todo -> URL.revokeObjectURL
} else {
setContent(<textarea style={{ width: '100%', height: '90%' }} value={await blob.text()} readOnly />);
}
setModalVisible(true);
})
}
const onDownloadClick = (ev, attachmentId) => {
secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
.then(resp => {
const contentDispositionHeader = resp.headers.get('Content-Disposition');
const filenameRe = new RegExp(/filename="(.*)";/)
const filename = filenameRe.exec(contentDispositionHeader)[1]
return Promise.all([resp.blob(), filename]);
})
.then((values) => {
const blob = values[0];
const filename = values[1];
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
})
}
const onDeleteAttachmentClick = (ev, attachmentId) => {
deleteAttachmentById(attachmentId)
.then(() => reloadAttachments());
}
const safeResolveMime = mimeType => {
try {
return resolveMime(mimeType)['name']
} catch (err) {
console.error(err);
return mimeType;
}
}
if (!attachments) {
return <Loading />
}
return <>
<ModalDialog visible={modalVisible} title="Preview output" onModalClose={onModalClose} style={{ overflow: 'auto', width: '80%', height: '80%', maxHeight: '80%' }}>
{content}
</ModalDialog>
<Table>
<Thead>
<Tr>
<Th>Filename</Th>
<Th>Mimetype</Th>
<Th>File size</Th>
<Th>Upload date</Th>
<Th>Uploaded by</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{attachments.length === 0 && <NoResultsTableRow numColumns={6} />}
{attachments.map((attachment, index) =>
<Tr key={index}>
<Td>{attachment.client_file_name}</Td>
<Td><span title={safeResolveMime(attachment.file_mimetype)}>{attachment.file_mimetype}</span></Td>
<Td><FileSizeSpan fileSize={attachment.file_size} /></Td>
<Td><RelativeDateFormatter date={attachment.insert_ts} /></Td>
<Td><UserLink userId={attachment.submitter_uid}>{attachment.submitter_name}</UserLink></Td>
<Td style={{ display: "flex" }}>
<SecondaryButton onClick={ev => onViewClick(ev, attachment.id)}>View</SecondaryButton>
<SecondaryButton onClick={ev => onDownloadClick(ev, attachment.id)}>Download</SecondaryButton>
<DeleteIconButton onClick={ev => onDeleteAttachmentClick(ev, attachment.id)} />
</Td>
</Tr>
)}
</Tbody>
</Table>
</>
}
Example #26
Source File: SubmissionReviewView.jsx From scaffold-directory with MIT License | 4 votes |
export default function SubmissionReviewView({ userProvider }) {
const address = useUserAddress(userProvider);
const [challenges, setChallenges] = React.useState([]);
const [isLoadingChallenges, setIsLoadingChallenges] = React.useState(true);
const [draftBuilds, setDraftBuilds] = React.useState([]);
const [isLoadingDraftBuilds, setIsLoadingDraftBuilds] = React.useState(true);
const toast = useToast({ position: "top", isClosable: true });
const toastVariant = useColorModeValue("subtle", "solid");
const { secondaryFontColor } = useCustomColorModes();
const fetchSubmittedChallenges = useCallback(async () => {
setIsLoadingChallenges(true);
let fetchedChallenges;
try {
fetchedChallenges = await getSubmittedChallenges(address);
} catch (error) {
toast({
description: "There was an error getting the submitted challenges. Please try again",
status: "error",
variant: toastVariant,
});
setIsLoadingChallenges(false);
return;
}
setChallenges(fetchedChallenges.sort(bySubmittedTimestamp));
setIsLoadingChallenges(false);
}, [address, toastVariant, toast]);
const fetchSubmittedBuilds = useCallback(async () => {
setIsLoadingDraftBuilds(true);
let fetchedDraftBuilds;
try {
fetchedDraftBuilds = await getDraftBuilds(address);
} catch (error) {
toast({
description: "There was an error getting the draft builds. Please try again",
status: "error",
variant: toastVariant,
});
setIsLoadingDraftBuilds(false);
return;
}
setDraftBuilds(fetchedDraftBuilds.sort(bySubmittedTimestamp));
setIsLoadingDraftBuilds(false);
}, [address, toastVariant, toast]);
useEffect(() => {
if (!address) {
return;
}
fetchSubmittedChallenges();
// eslint-disable-next-line
}, [address]);
useEffect(() => {
if (!address) {
return;
}
fetchSubmittedBuilds();
// eslint-disable-next-line
}, [address]);
const handleSendChallengeReview = reviewType => async (userAddress, challengeId, comment) => {
let signMessage;
try {
signMessage = await getChallengeReviewSignMessage(address, userAddress, challengeId, reviewType);
} catch (error) {
toast({
description: " Sorry, the server is overloaded. ???",
status: "error",
variant: toastVariant,
});
return;
}
let signature;
try {
signature = await userProvider.send("personal_sign", [signMessage, address]);
} catch (error) {
toast({
description: "Couldn't get a signature from the Wallet",
status: "error",
variant: toastVariant,
});
console.error(error);
return;
}
try {
await patchChallengeReview(address, signature, { userAddress, challengeId, newStatus: reviewType, comment });
} catch (error) {
if (error.status === 401) {
toast({
status: "error",
description: "Submission Error. You don't have the required role.",
variant: toastVariant,
});
return;
}
toast({
status: "error",
description: "Submission Error. Please try again.",
variant: toastVariant,
});
return;
}
toast({
description: "Review submitted successfully",
status: "success",
variant: toastVariant,
});
fetchSubmittedChallenges();
};
const handleSendBuildReview = reviewType => async (userAddress, buildId) => {
let signMessage;
try {
signMessage = await getBuildReviewSignMessage(address, buildId, reviewType);
} catch (error) {
toast({
description: " Sorry, the server is overloaded. ???",
status: "error",
variant: toastVariant,
});
return;
}
let signature;
try {
signature = await userProvider.send("personal_sign", [signMessage, address]);
} catch (error) {
toast({
description: "Couldn't get a signature from the Wallet",
status: "error",
variant: toastVariant,
});
return;
}
try {
await patchBuildReview(address, signature, { userAddress, buildId, newStatus: reviewType });
} catch (error) {
if (error.status === 401) {
toast({
status: "error",
description: "Submission Error. You don't have the required role.",
variant: toastVariant,
});
return;
}
toast({
status: "error",
description: "Submission Error. Please try again.",
variant: toastVariant,
});
return;
}
toast({
description: "Review submitted successfully",
status: "success",
variant: toastVariant,
});
fetchSubmittedBuilds();
};
return (
<Container maxW="container.lg">
<Container maxW="container.md" centerContent>
<Heading as="h1">Review Submissions</Heading>
<Text color={secondaryFontColor}>Pending submissions to validate.</Text>
<Text color={secondaryFontColor} mb="6">
Check our{" "}
<Link href={RUBRIC_URL} color="teal.500" isExternal>
Grading Rubric
</Link>
.
</Text>
</Container>
<Heading as="h2" size="lg" mt={6} mb={4}>
Challenges
</Heading>
<Box overflowX="auto">
{isLoadingChallenges ? (
<ChallengesTableSkeleton />
) : (
<Table>
<Thead>
<Tr>
<Th>Builder</Th>
<Th>Challenge</Th>
<Th>Submitted time</Th>
<Th>Actions</Th>
</Tr>
</Thead>
<Tbody>
{!challenges || challenges.length === 0 ? (
<Tr>
<Td colSpan={6}>
<Text color={secondaryFontColor} textAlign="center" mb={4}>
<Icon as={HeroIconInbox} w={6} h={6} color={secondaryFontColor} mt={6} mb={4} />
<br />
All challenges have been reviewed
</Text>
</Td>
</Tr>
) : (
challenges.map(challenge => (
<ChallengeReviewRow
key={`${challenge.userAddress}_${challenge.id}`}
challenge={challenge}
isLoading={isLoadingChallenges}
approveClick={handleSendChallengeReview("ACCEPTED")}
rejectClick={handleSendChallengeReview("REJECTED")}
userProvider={userProvider}
/>
))
)}
</Tbody>
</Table>
)}
</Box>
<Heading as="h2" size="lg" mt={6} mb={4}>
Builds
</Heading>
<Box overflowX="auto">
{isLoadingDraftBuilds ? (
<BuildsTableSkeleton />
) : (
<Table mb={4}>
<Thead>
<Tr>
<Th>Builder</Th>
<Th>Build Name</Th>
<Th>Description</Th>
<Th>Branch URL</Th>
<Th>Submitted time</Th>
<Th>Actions</Th>
</Tr>
</Thead>
<Tbody>
{!draftBuilds || draftBuilds.length === 0 ? (
<Tr>
<Td colSpan={5}>
<Text color={secondaryFontColor} textAlign="center" mb={4}>
<Icon as={HeroIconInbox} w={6} h={6} color={secondaryFontColor} mt={6} mb={4} />
<br />
All builds have been reviewed
</Text>
</Td>
</Tr>
) : (
draftBuilds.map(build => (
<BuildReviewRow
key={`${build.userAddress}_${build.id}`}
build={build}
isLoading={isLoadingDraftBuilds}
approveClick={handleSendBuildReview("ACCEPTED")}
rejectClick={handleSendBuildReview("REJECTED")}
/>
))
)}
</Tbody>
</Table>
)}
</Box>
</Container>
);
}