From e58b4fac0d2d8440701bd2fdad55b554088cc999 Mon Sep 17 00:00:00 2001 From: aidencao Date: Mon, 31 Jul 2023 10:32:59 +0800 Subject: [PATCH] feat(dcellar-web-ui): add sp meta --- .../src/components/common/DCSelect/index.tsx | 34 ++-- .../src/components/common/SvgIcon/RefLink.svg | 3 + .../components/layout/Header/GlobalTasks.tsx | 7 + apps/dcellar-web-ui/src/facade/sp.ts | 7 + .../buckets/List/components/SPSelector.tsx | 191 ++++++++++++++---- .../modules/object/components/ObjectList.tsx | 8 +- apps/dcellar-web-ui/src/pages/api/sp-meta.ts | 17 ++ .../dcellar-web-ui/src/store/slices/apollo.ts | 2 + apps/dcellar-web-ui/src/store/slices/sp.ts | 28 ++- 9 files changed, 229 insertions(+), 68 deletions(-) create mode 100644 apps/dcellar-web-ui/src/components/common/SvgIcon/RefLink.svg create mode 100644 apps/dcellar-web-ui/src/pages/api/sp-meta.ts diff --git a/apps/dcellar-web-ui/src/components/common/DCSelect/index.tsx b/apps/dcellar-web-ui/src/components/common/DCSelect/index.tsx index 16dcb17f..4d6d910d 100644 --- a/apps/dcellar-web-ui/src/components/common/DCSelect/index.tsx +++ b/apps/dcellar-web-ui/src/components/common/DCSelect/index.tsx @@ -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; @@ -121,22 +123,8 @@ export function Select(props: DCSelectProps) { onEnter={onEnter} /> - - {header && ( - - {header} - - )} + + {header} - {item.label} + {isSelected && } {item.label} ); @@ -258,3 +248,9 @@ const NoResult = () => { ); }; + +const Tick = styled(TickIcon)` + color: #00ba34; + position: absolute; + left: 8px; +`; diff --git a/apps/dcellar-web-ui/src/components/common/SvgIcon/RefLink.svg b/apps/dcellar-web-ui/src/components/common/SvgIcon/RefLink.svg new file mode 100644 index 00000000..cd754740 --- /dev/null +++ b/apps/dcellar-web-ui/src/components/common/SvgIcon/RefLink.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx b/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx index 83dfbb8b..8207d1d9 100644 --- a/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx +++ b/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx @@ -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(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); @@ -128,5 +130,10 @@ export const GlobalTasks = memo(function GlobalTasks() { } }, [sealQueue.join(''), counter]); + useAsyncEffect(async () => { + if (!loginAccount || !SP_RECOMMEND_META) return; + dispatch(setupSpMeta()); + }, [loginAccount, SP_RECOMMEND_META]); + return <>; }); diff --git a/apps/dcellar-web-ui/src/facade/sp.ts b/apps/dcellar-web-ui/src/facade/sp.ts index e11ea402..2fc226af 100644 --- a/apps/dcellar-web-ui/src/facade/sp.ts +++ b/apps/dcellar-web-ui/src/facade/sp.ts @@ -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(); @@ -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>('/api/sp-meta'); + return data; +}; diff --git a/apps/dcellar-web-ui/src/modules/buckets/List/components/SPSelector.tsx b/apps/dcellar-web-ui/src/modules/buckets/List/components/SPSelector.tsx index 67fdea89..c9579bac 100644 --- a/apps/dcellar-web-ui/src/modules/buckets/List/components/SPSelector.tsx +++ b/apps/dcellar-web-ui/src/modules/buckets/List/components/SPSelector.tsx @@ -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); @@ -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: , - 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: , + value: operatorAddress, + name, + endpoint: item.endpoint, + }; + }); + }, [sps, spMeta]); return (