Skip to content

Commit

Permalink
feat(dcellar-web-ui): add sp meta
Browse files Browse the repository at this point in the history
  • Loading branch information
aiden-cao committed Jul 31, 2023
1 parent 34e924c commit e58b4fa
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 68 deletions.
34 changes: 15 additions & 19 deletions apps/dcellar-web-ui/src/components/common/DCSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ import {
InputProps,
} from '@totejs/uikit';
import React, { useEffect, useRef, useState } from 'react';
import TickIcon from '@/components/common/SvgIcon/TickIcon.svg';

import noResultImage from '@/public/images/common/no-result.png';
import { useKeyDown } from '@/hooks/useKeyDown';
import { useSaveFuncRef } from '@/hooks/useSaveFuncRef';
import { GAClick } from '@/components/common/GATracker';
import styled from '@emotion/styled';

interface ListItemProps extends MenuItemProps {
gaClickName?: string;
Expand Down Expand Up @@ -121,22 +123,8 @@ export function Select(props: DCSelectProps) {
onEnter={onEnter}
/>

<MenuList border="1px solid readable.border" borderRadius={8} {...listProps}>
{header && (
<Box
color="#2AA372"
fontSize={12}
lineHeight="15px"
bg="bg.bottom"
py={8}
px={24}
fontWeight={500}
borderBottom="1px solid readable.border"
{...headerProps}
>
{header}
</Box>
)}
<MenuList mt={5} border="1px solid readable.border" borderRadius={8} {...listProps}>
{header}

<Box
maxH={220}
Expand All @@ -158,8 +146,10 @@ export function Select(props: DCSelectProps) {
return (
<GAClick key={item.value} name={gaClickName}>
<MenuItem
px={24}
py={8}
as="div"
position="relative"
px={0}
py={0}
transitionDuration="normal"
transitionProperty="colors"
bg={isSelected ? rgba('#00BA34', 0.1) : undefined}
Expand All @@ -172,7 +162,7 @@ export function Select(props: DCSelectProps) {
}}
{...restItemProps}
>
{item.label}
{isSelected && <Tick />} {item.label}
</MenuItem>
</GAClick>
);
Expand Down Expand Up @@ -258,3 +248,9 @@ const NoResult = () => {
</Center>
);
};

const Tick = styled(TickIcon)`
color: #00ba34;
position: absolute;
left: 8px;
`;
3 changes: 3 additions & 0 deletions apps/dcellar-web-ui/src/components/common/SvgIcon/RefLink.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ import axios from 'axios';
import { headObject, queryLockFee } from '@/facade/object';
import Long from 'long';
import { formatLockFee } from '@/utils/object';
import { setupSpMeta } from '@/store/slices/sp';

interface GlobalTasksProps {}

export const GlobalTasks = memo<GlobalTasksProps>(function GlobalTasks() {
const dispatch = useAppDispatch();
const { SP_RECOMMEND_META } = useAppSelector((root) => root.apollo);
const { loginAccount } = useAppSelector((root) => root.persist);
const { spInfo } = useAppSelector((root) => root.sp);
const { primarySp } = useAppSelector((root) => root.object);
Expand Down Expand Up @@ -128,5 +130,10 @@ export const GlobalTasks = memo<GlobalTasksProps>(function GlobalTasks() {
}
}, [sealQueue.join(''), counter]);

useAsyncEffect(async () => {
if (!loginAccount || !SP_RECOMMEND_META) return;
dispatch(setupSpMeta());
}, [loginAccount, SP_RECOMMEND_META]);

return <></>;
});
7 changes: 7 additions & 0 deletions apps/dcellar-web-ui/src/facade/sp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { getClient } from '@/base/client';
import { resolve } from '@/facade/common';
import { commonFault } from '@/facade/error';
import axios from 'axios';
import { SpMeta } from '@/store/slices/sp';

export const getStorageProviders = async () => {
const client = await getClient();
Expand All @@ -9,3 +11,8 @@ export const getStorageProviders = async () => {
console.log('getStorageProviders', performance.now() - start);
return (sps || []).filter((sp) => sp.endpoint.startsWith('https'));
};

export const getSpMeta = async () => {
const { data } = await axios.get<Array<SpMeta>>('/api/sp-meta');
return data;
};
191 changes: 150 additions & 41 deletions apps/dcellar-web-ui/src/modules/buckets/List/components/SPSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { Box, Text } from '@totejs/uikit';
import { Box, Flex, Text, Tooltip } from '@totejs/uikit';
import { IDCSelectOption, Select } from '@/components/common/DCSelect';
import { trimLongStr } from '@/utils/string';
import { useAppSelector } from '@/store';
import { useMount } from 'ahooks';
import { SpItem } from '@/store/slices/sp';
import styled from '@emotion/styled';
import { ColoredInfoIcon } from '@totejs/icons';
import RefLink from '@/components/common/SvgIcon/RefLink.svg';
import { GREENFIELD_CHAIN_EXPLORER_URL } from '@/base/env';
import { formatBytes } from '@/modules/file/utils';
import BigNumber from 'bignumber.js';
import { transientOptions } from '@/utils/transientOptions';
import { css } from '@emotion/react';
import { sortBy } from 'lodash-es';

interface SPSelector {
onChange: (value: SpItem) => void;
}

export function SPSelector(props: SPSelector) {
const { sps, spInfo, oneSp } = useAppSelector((root) => root.sp);
const { sps, spInfo, oneSp, spMeta } = useAppSelector((root) => root.sp);
const len = sps.length;
const [sp, setSP] = useState({} as SpItem);
const [total, setTotal] = useState(0);
Expand Down Expand Up @@ -45,26 +54,42 @@ export function SPSelector(props: SPSelector) {
return tmpValue.includes(tmpKeyword) || tmpName.includes(tmpKeyword);
};

const options = useMemo(
() =>
sps.map((item) => {
const { operatorAddress, moniker: name, endpoint } = item;
return {
label: <OptionItem address={operatorAddress} name={name} endpoint={endpoint} />,
value: operatorAddress,
name,
endpoint: item.endpoint,
};
}),
[sps],
);
const options = useMemo(() => {
const sorted = sortBy(sps, [
(sp) => {
const meta = spMeta[sp.operatorAddress];
return meta ? meta.Latency : Infinity;
},
]);
return sorted.map((item) => {
const { operatorAddress, moniker: name, endpoint } = item;
return {
label: <OptionItem address={operatorAddress} name={name} endpoint={endpoint} />,
value: operatorAddress,
name,
endpoint: item.endpoint,
};
});
}, [sps, spMeta]);

return (
<Select
value={sp.operatorAddress}
text={renderItem(sp.moniker, sp.operatorAddress)}
options={options}
header={`Primary Storage Provider (${total})`}
header={
<Row>
<TH w={200}>SP list</TH>
<TH w={100}>Free Quota</TH>
<TH w={120}>
Storage Fee{' '}
<Tooltip content="BNB/GB/Month" placement="bottom-start">
<ColoredInfoIcon boxSize={16} cursor="pointer" />
</Tooltip>
</TH>
<TH w={100}>Latency</TH>
</Row>
}
onChange={onChangeSP}
onSearchFilter={onSearchFilter}
onSearch={onSearch}
Expand All @@ -80,34 +105,118 @@ const renderItem = (moniker: string, address: string) => {
};

function OptionItem(props: any) {
const { spMeta } = useAppSelector((root) => root.sp);
const { address, name, endpoint } = props;
const meta = spMeta[address];

return (
<Box key={address} display="flex" flexDir="column" alignItems="flex-start" whiteSpace="normal">
<Text
fontSize={16}
lineHeight="19px"
fontWeight={400}
w="100%"
color="readable.top.secondary"
noOfLines={1}
<Flex key={address} alignItems="center">
<TD
w={200}
key={address}
display="flex"
flexDir="column"
alignItems="flex-start"
whiteSpace="normal"
>
{renderItem(name, address)}
</Text>
{name && (
<Text
mt={2}
fontSize={12}
transformOrigin="0 50%"
transform={'scale(0.85)'}
lineHeight="18px"
fontWeight={400}
color="readable.secondary"
noOfLines={1}
>
{endpoint}
</Text>
)}
</Box>
<Flex alignItems="center" w="100%">
<Text
maxW="max-content"
minW={0}
flex={1}
lineHeight="17px"
fontSize={14}
fontWeight={400}
w="100%"
color="readable.top.secondary"
noOfLines={1}
>
{name}
</Text>
<A
href={`${GREENFIELD_CHAIN_EXPLORER_URL}/account/${address}`}
target="_blank"
onClick={(e) => e.stopPropagation()}
>
<RefLink />
</A>
</Flex>

<Tooltip content={endpoint} placement="bottom-start">
<Text
lineHeight="14px"
wordBreak="break-all"
fontSize={12}
transformOrigin="0 50%"
transform={'scale(0.85)'}
fontWeight={400}
color="#76808F"
noOfLines={1}
>
{endpoint}
</Text>
</Tooltip>
</TD>
<TD w={100}>{meta ? formatBytes(meta.FreeReadQuota) : '--'}</TD>
<TD w={120}>{meta ? Number(BigNumber(meta.StorePrice).toFixed(5)) : '--'}</TD>
<TD $dot={meta?.Latency}>{meta ? meta.Latency + 'ms' : '--'}</TD>
</Flex>
);
}

const A = styled.a`
:hover {
color: #00ba34;
}
margin-left: 4px;
`;

const Row = styled.div`
display: flex;
align-items: center;
border-bottom: 1px solid #e6e8ea;
background: #f5f5f5;
`;

const TH = styled(Box)`
padding: 8px;
font-size: 12px;
font-weight: 500;
height: 32px;
&:first-of-type {
padding-left: 12px;
padding-right: 12px;
}
`;

const TD = styled(Box, transientOptions)<{ $dot?: number }>`
position: relative;
padding: 8px;
font-size: 14px;
color: #474d57;
font-weight: 400;
&:first-of-type {
padding-left: 32px;
}
${(props) =>
props.$dot &&
css`
:before {
position: relative;
top: -1px;
margin-right: 4px;
display: inline-flex;
content: '';
width: 8px;
height: 8px;
border-radius: 100%;
background-color: ${props.$dot < 100
? '#00BA34'
: props.$dot < 200
? '#EEBE11'
: '#EE3911'};
}
`}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,8 @@ export const ObjectList = memo<ObjectListProps>(function ObjectList() {
let operations: string[] = [];
const isCurRow = rowIndex === index;
const isFolder = record.objectName.endsWith('/');
const isPublic = record.visibility === VisibilityType.VISIBILITY_TYPE_PUBLIC_READ;
const isSealed = record.objectStatus === OBJECT_SEALED_STATUS;

if (!isPublic) {
fitActions = Actions.filter((a) => a.value !== 'share');
}
if (isSealed) {
fitActions = fitActions.filter((a) => a.value !== 'cancel');
} else {
Expand All @@ -306,7 +302,7 @@ export const ObjectList = memo<ObjectListProps>(function ObjectList() {
if (isFolder && !owner) {
fitActions = [];
}
isCurRow && !isFolder && isPublic && operations.push('share');
isCurRow && !isFolder && operations.push('share');
isCurRow && !isFolder && isSealed && operations.push('download');

return (
Expand Down Expand Up @@ -358,7 +354,7 @@ export const ObjectList = memo<ObjectListProps>(function ObjectList() {
return (
<>
{editCreate && <CreateFolder refetch={refetch} />}
{editDelete?.objectName && !deleteFolderNotEmpty &&<DeleteObject refetch={refetch} />}
{editDelete?.objectName && !deleteFolderNotEmpty && <DeleteObject refetch={refetch} />}
{deleteFolderNotEmpty && <FolderNotEmpty />}
{statusDetail.title && <StatusDetail />}
{editDetail?.objectName && <DetailObject />}
Expand Down
17 changes: 17 additions & 0 deletions apps/dcellar-web-ui/src/pages/api/sp-meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NextApiRequest, NextApiResponse } from 'next';
import axios from 'axios';

// @ts-ignore
// eslint-disable-next-line
export default async (req: NextApiRequest, res: NextApiResponse) => {
const endpoint = ((global as any).__GLOBAL_CONFIG || {}).SP_RECOMMEND_META;

if (!endpoint) res.json([]);
try {
const { data } = await axios.post(endpoint, { data: {} });
res.json(data);
} catch (e) {
console.log(e);
res.json([]);
}
};
Loading

0 comments on commit e58b4fa

Please sign in to comment.