From c0c668150548797b6db85c807194d10370183e9c Mon Sep 17 00:00:00 2001 From: aidencao Date: Tue, 29 Aug 2023 11:43:05 +0800 Subject: [PATCH] feat(dcellar-web-ui): remove getsp url by bucket --- .../components/common/DCTable/ActionMenu.tsx | 6 +- .../components/layout/Header/GlobalTasks.tsx | 189 ++++++++++-------- apps/dcellar-web-ui/src/facade/object.ts | 3 +- .../accounts/components/OwnerAccount.tsx | 17 +- .../accounts/components/PaymentAccounts.tsx | 15 +- .../src/modules/file/utils/file.ts | 1 + .../file/utils/generateGetObjectOptions.ts | 3 +- .../file/utils/generatePubObjectOptions.ts | 3 +- .../src/modules/object/index.tsx | 23 +-- .../src/modules/share/SharedFile.tsx | 22 +- .../src/modules/upload/UploadObjects.tsx | 10 +- apps/dcellar-web-ui/src/pages/share/index.tsx | 19 +- .../dcellar-web-ui/src/store/slices/bucket.ts | 14 +- apps/dcellar-web-ui/src/store/slices/sp.ts | 23 ++- 14 files changed, 181 insertions(+), 167 deletions(-) diff --git a/apps/dcellar-web-ui/src/components/common/DCTable/ActionMenu.tsx b/apps/dcellar-web-ui/src/components/common/DCTable/ActionMenu.tsx index b748b482..3184fe2c 100644 --- a/apps/dcellar-web-ui/src/components/common/DCTable/ActionMenu.tsx +++ b/apps/dcellar-web-ui/src/components/common/DCTable/ActionMenu.tsx @@ -76,7 +76,7 @@ export const ActionMenu = memo(function ActionMenu({ marginRight={'8px'} onClick={() => onChange(m)} > - + ); case 'transfer_out': @@ -87,7 +87,7 @@ export const ActionMenu = memo(function ActionMenu({ marginRight={'8px'} onClick={() => onChange(m)} > - + ); case 'send': @@ -98,7 +98,7 @@ export const ActionMenu = memo(function ActionMenu({ marginRight={'8px'} onClick={() => onChange(m)} > - + ); // payment account list 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 fd662e2d..5b2c4221 100644 --- a/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx +++ b/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx @@ -15,7 +15,10 @@ import { useChecksumApi } from '@/modules/checksum'; import { useAsyncEffect } from 'ahooks'; import { getDomain } from '@/utils/getDomain'; import { getSpOffChainData } from '@/store/slices/persist'; -import { TMakePutObjectHeaders, makePutObjectHeaders } from '@/modules/file/utils/generatePubObjectOptions'; +import { + TMakePutObjectHeaders, + makePutObjectHeaders, +} from '@/modules/file/utils/generatePubObjectOptions'; import axios from 'axios'; import { headObject } from '@/facade/object'; import { reverseVisibilityType } from '@/utils/constant'; @@ -40,11 +43,16 @@ export const GlobalTasks = memo(function GlobalTasks() { const checksumApi = useChecksumApi(); const [counter, setCounter] = useState(0); const queue = useAppSelector(selectUploadQueue(loginAccount)); - const folderInfos = keyBy(queue.filter((q) => q.waitFile.name.endsWith('/')), 'name'); + const folderInfos = keyBy( + queue.filter((q) => q.waitFile.name.endsWith('/')), + 'name', + ); const upload = queue.filter((t) => t.status === 'UPLOAD'); const ready = queue.filter((t) => { const isFolder = t.waitFile.name.endsWith('/'); - const parentFolder = isFolder ? t.waitFile.name.split('/').slice(0, -1).join('/') + '/' : t.waitFile.relativePath + '/'; + const parentFolder = isFolder + ? t.waitFile.name.split('/').slice(0, -1).join('/') + '/' + : t.waitFile.relativePath + '/'; if (!folderInfos[parentFolder]) { return t.status === 'READY'; } @@ -68,11 +76,13 @@ export const GlobalTasks = memo(function GlobalTasks() { const res = await checksumApi?.generateCheckSumV2(hashTask.waitFile.file); console.log('hashing time', performance.now() - a); if (isEmpty(res)) { - return dispatch(setupUploadTaskErrorMsg({ - account: loginAccount, - task: hashTask, - errorMsg: 'calculating hash error', - })) + return dispatch( + setupUploadTaskErrorMsg({ + account: loginAccount, + task: hashTask, + errorMsg: 'calculating hash error', + }), + ); } const { expectCheckSums } = res!; dispatch( @@ -87,10 +97,11 @@ export const GlobalTasks = memo(function GlobalTasks() { // todo refactor const runUploadTask = async (task: UploadFile) => { // 1. get approval from sp - const domain = getDomain(); const isFolder = task.waitFile.name.endsWith('/'); const { seedString } = await dispatch(getSpOffChainData(loginAccount, task.spAddress)); - const finalName = [...task.prefixFolders, task.waitFile.relativePath, task.waitFile.name].filter(item => !!item).join('/'); + const finalName = [...task.prefixFolders, task.waitFile.relativePath, task.waitFile.name] + .filter((item) => !!item) + .join('/'); const createObjectPayload: TBaseGetCreateObject = { bucketName: task.bucketName, objectName: finalName, @@ -103,16 +114,15 @@ export const GlobalTasks = memo(function GlobalTasks() { const [createObjectTx, _createError] = await genCreateObjectTx(createObjectPayload, { type: 'ECDSA', privateKey: tmpAccount.privateKey, - }).then( - resolve, - createTxFault, - ); + }).then(resolve, createTxFault); if (_createError) { - return dispatch(setupUploadTaskErrorMsg({ - account: loginAccount, - task, - errorMsg: _createError, - })) + return dispatch( + setupUploadTaskErrorMsg({ + account: loginAccount, + task, + errorMsg: _createError, + }), + ); } const [simulateInfo, simulateError] = await createObjectTx! @@ -121,11 +131,13 @@ export const GlobalTasks = memo(function GlobalTasks() { }) .then(resolve, simulateFault); if (!simulateInfo || simulateError) { - return dispatch(setupUploadTaskErrorMsg({ - account: loginAccount, - task, - errorMsg: simulateError, - })) + return dispatch( + setupUploadTaskErrorMsg({ + account: loginAccount, + task, + errorMsg: simulateError, + }), + ); } const broadcastPayload = { @@ -140,73 +152,90 @@ export const GlobalTasks = memo(function GlobalTasks() { .broadcast(broadcastPayload) .then(resolve, broadcastFault); if (!res || error) { - return dispatch(setupUploadTaskErrorMsg({ - account: loginAccount, - task, - errorMsg: error, - })) + return dispatch( + setupUploadTaskErrorMsg({ + account: loginAccount, + task, + errorMsg: error, + }), + ); } - const fullObjectName = [...task.prefixFolders, task.waitFile.relativePath, task.waitFile.name].filter(item => !!item).join('/'); + const fullObjectName = [...task.prefixFolders, task.waitFile.relativePath, task.waitFile.name] + .filter((item) => !!item) + .join('/'); const payload: TMakePutObjectHeaders = { bucketName: task.bucketName, objectName: fullObjectName, body: task.waitFile.file, endpoint: spInfo[task.spAddress].endpoint, txnHash: res.transactionHash, - } + }; const authType = { type: 'EDDSA', seed: seedString, domain: window.location.origin, address: loginAccount, } as AuthType; - const [uploadOptions, gpooError] = await makePutObjectHeaders(payload, authType).then(resolve, commonFault); + const [uploadOptions, gpooError] = await makePutObjectHeaders(payload, authType).then( + resolve, + commonFault, + ); if (!uploadOptions || gpooError) { - return dispatch(setupUploadTaskErrorMsg({ - account: loginAccount, - task, - errorMsg: gpooError, - })) + return dispatch( + setupUploadTaskErrorMsg({ + account: loginAccount, + task, + errorMsg: gpooError, + }), + ); } const { url, headers } = uploadOptions; if (isFolder) { - dispatch(updateUploadStatus({ - account: loginAccount, - ids: [task.id], - status: 'SEAL', - })); + dispatch( + updateUploadStatus({ + account: loginAccount, + ids: [task.id], + status: 'SEAL', + }), + ); } else { - axios.put(url, task.waitFile.file, { - async onUploadProgress(progressEvent) { - const progress = Math.round((progressEvent.loaded / (progressEvent.total as number)) * 100); - await dispatch(progressFetchList(task)); - dispatch(updateUploadProgress({ account: loginAccount, id: task.id, progress })); - }, - - headers: { - Authorization: headers.get('Authorization'), - 'content-type': headers.get('content-type'), - 'x-gnfd-app-domain': headers.get('x-gnfd-app-domain'), - 'x-gnfd-content-sha256': headers.get('x-gnfd-content-sha256'), - 'x-gnfd-date': headers.get('x-gnfd-date'), - 'x-gnfd-expiry-timestamp': headers.get('x-gnfd-expiry-timestamp'), - 'x-gnfd-txn-hash': headers.get('x-gnfd-txn-hash'), - 'x-gnfd-user-address': headers.get('x-gnfd-user-address'), - }, - }).catch(async (e: Response | any) => { - console.log('upload error', e); - const { message } = await parseErrorXml(e); - setTimeout(() => { - dispatch(setupUploadTaskErrorMsg({ - account: loginAccount, - task, - errorMsg: message || e?.message || 'upload error', - })) - }, 200); - }) - }; - } + axios + .put(url, task.waitFile.file, { + async onUploadProgress(progressEvent) { + const progress = Math.round( + (progressEvent.loaded / (progressEvent.total as number)) * 100, + ); + await dispatch(progressFetchList(task)); + dispatch(updateUploadProgress({ account: loginAccount, id: task.id, progress })); + }, + + headers: { + Authorization: headers.get('Authorization'), + 'content-type': headers.get('content-type'), + 'x-gnfd-app-domain': headers.get('x-gnfd-app-domain'), + 'x-gnfd-content-sha256': headers.get('x-gnfd-content-sha256'), + 'x-gnfd-date': headers.get('x-gnfd-date'), + 'x-gnfd-expiry-timestamp': headers.get('x-gnfd-expiry-timestamp'), + 'x-gnfd-txn-hash': headers.get('x-gnfd-txn-hash'), + 'x-gnfd-user-address': headers.get('x-gnfd-user-address'), + }, + }) + .catch(async (e: Response | any) => { + console.log('upload error', e); + const { message } = await parseErrorXml(e); + setTimeout(() => { + dispatch( + setupUploadTaskErrorMsg({ + account: loginAccount, + task, + errorMsg: message || e?.message || 'upload error', + }), + ); + }, 200); + }); + } + }; useAsyncEffect(async () => { if (!select1Task.length) return; dispatch(updateUploadStatus({ ids: select1Task, status: 'UPLOAD', account: loginAccount })); @@ -221,15 +250,19 @@ export const GlobalTasks = memo(function GlobalTasks() { const _tasks = await Promise.all( tasks.map(async (task) => { const { bucketName, prefixFolders, waitFile } = task; - const objectName = [...prefixFolders, waitFile.relativePath, waitFile.name].filter(item => !!item).join('/'); + const objectName = [...prefixFolders, waitFile.relativePath, waitFile.name] + .filter((item) => !!item) + .join('/'); const objectInfo = await headObject(bucketName, objectName); if (!objectInfo || ![0, 1].includes(objectInfo.objectStatus)) { - dispatch(setupUploadTaskErrorMsg({ - account: loginAccount, - task, - errorMsg: 'Something went wrong.', - })) + dispatch( + setupUploadTaskErrorMsg({ + account: loginAccount, + task, + errorMsg: 'Something went wrong.', + }), + ); return -1; } if (objectInfo.objectStatus === 1) { diff --git a/apps/dcellar-web-ui/src/facade/object.ts b/apps/dcellar-web-ui/src/facade/object.ts index 4dd86b29..dd82558b 100644 --- a/apps/dcellar-web-ui/src/facade/object.ts +++ b/apps/dcellar-web-ui/src/facade/object.ts @@ -142,7 +142,7 @@ export const getAuthorizedLink = async ( seedString: string, view?: '0' | '1', ): Promise<[null, ErrorMsg] | [string]> => { - const { address, objectInfo } = params; + const { address, objectInfo, primarySp } = params; const { bucketName, objectName } = objectInfo; const [url, error] = await generateGetObjectOptions({ bucketName, @@ -150,6 +150,7 @@ export const getAuthorizedLink = async ( address, view, seedString, + endpoint: primarySp.endpoint, }).then(resolve, commonFault); if (!url) return [null, error!]; return [url]; diff --git a/apps/dcellar-web-ui/src/modules/accounts/components/OwnerAccount.tsx b/apps/dcellar-web-ui/src/modules/accounts/components/OwnerAccount.tsx index 30fc14c9..281fdea0 100644 --- a/apps/dcellar-web-ui/src/modules/accounts/components/OwnerAccount.tsx +++ b/apps/dcellar-web-ui/src/modules/accounts/components/OwnerAccount.tsx @@ -1,7 +1,7 @@ import { Box, Flex, Link } from '@totejs/uikit'; import { ColumnProps } from 'antd/es/table'; import React, { useState } from 'react'; -import { AlignType, DCTable } from '@/components/common/DCTable'; +import { DCTable } from '@/components/common/DCTable'; import { useAppDispatch, useAppSelector } from '@/store'; import { TAccount, setEditOwnerDetail } from '@/store/slices/accounts'; import { isEmpty } from 'lodash-es'; @@ -19,7 +19,6 @@ const actions: ActionMenuItem[] = [ export const OwnerAccount = () => { const dispatch = useAppDispatch(); - const [rowIndex, setRowIndex] = useState(-1); const { ownerAccount } = useAppSelector((root) => root.accounts); const data = ownerAccount?.address ? [ownerAccount] : []; const router = useRouter(); @@ -68,12 +67,10 @@ export const OwnerAccount = () => { }, { key: 'Operation', - title: 'Operation', - align: 'center' as AlignType, + title: <>, width: 200, - render: (_: string, record: TAccount, index: number) => { - const isCurRow = rowIndex === index; - const operations = isCurRow ? ['transfer_in', 'transfer_out', 'send'] : []; + render: (_: string, record: TAccount) => { + const operations = ['transfer_in', 'transfer_out', 'send']; return ( { onClick: () => { dispatch(setEditOwnerDetail(record.address)); }, - onMouseEnter: () => { - setRowIndex(Number(index)); - }, - onMouseLeave: () => { - setRowIndex(-1); - }, })} > diff --git a/apps/dcellar-web-ui/src/modules/accounts/components/PaymentAccounts.tsx b/apps/dcellar-web-ui/src/modules/accounts/components/PaymentAccounts.tsx index fee2fcb1..e69765a1 100644 --- a/apps/dcellar-web-ui/src/modules/accounts/components/PaymentAccounts.tsx +++ b/apps/dcellar-web-ui/src/modules/accounts/components/PaymentAccounts.tsx @@ -27,7 +27,6 @@ const actions: ActionMenuItem[] = [ export const PaymentAccounts = () => { const dispatch = useAppDispatch(); - const [rowIndex, setRowIndex] = useState(-1); const router = useRouter(); const { PAList, isLoadingPAList, currentPAPage, ownerAccount } = useAppSelector( (root) => root.accounts, @@ -102,12 +101,10 @@ export const PaymentAccounts = () => { }, { key: 'Operation', - title: 'Operation', - align: 'center' as AlignType, + title: <>, width: 200, - render: (_: string, record: TAccount, index: number) => { - const isCurRow = rowIndex === index; - const operations = isCurRow ? ['deposit', 'withdraw'] : []; + render: (_: string, record: TAccount) => { + const operations = ['deposit', 'withdraw']; return ( { onClick: () => { dispatch(setEditPaymentDetail(record.address)); }, - onMouseEnter: () => { - setRowIndex(Number(index)); - }, - onMouseLeave: () => { - setRowIndex(-1); - }, })} > diff --git a/apps/dcellar-web-ui/src/modules/file/utils/file.ts b/apps/dcellar-web-ui/src/modules/file/utils/file.ts index b9709799..0c34595e 100644 --- a/apps/dcellar-web-ui/src/modules/file/utils/file.ts +++ b/apps/dcellar-web-ui/src/modules/file/utils/file.ts @@ -10,6 +10,7 @@ export interface getObjectPropsType { bucketName: string; objectName: string; duration?: number; + endpoint?: string; address: string; seedString: string; view?: '0' | '1'; diff --git a/apps/dcellar-web-ui/src/modules/file/utils/generateGetObjectOptions.ts b/apps/dcellar-web-ui/src/modules/file/utils/generateGetObjectOptions.ts index 154772ba..aabaed36 100644 --- a/apps/dcellar-web-ui/src/modules/file/utils/generateGetObjectOptions.ts +++ b/apps/dcellar-web-ui/src/modules/file/utils/generateGetObjectOptions.ts @@ -13,6 +13,7 @@ export const generateGetObjectOptions = async ( seedString, view = '1', duration = 24 * 60 * 60, + endpoint, } = configParam; const client = await getClient(); const auth: AuthType = { @@ -27,5 +28,5 @@ export const generateGetObjectOptions = async ( 'X-Gnfd-App-Domain': window.location.origin, 'X-Gnfd-Expiry-Timestamp': dayjs().add(duration, 'second').toISOString(), }; - return client.object.getObjectPreviewUrl({ bucketName, objectName, queryMap }, auth); + return client.object.getObjectPreviewUrl({ bucketName, objectName, queryMap, endpoint }, auth); }; diff --git a/apps/dcellar-web-ui/src/modules/file/utils/generatePubObjectOptions.ts b/apps/dcellar-web-ui/src/modules/file/utils/generatePubObjectOptions.ts index 8b979edf..f87a8322 100644 --- a/apps/dcellar-web-ui/src/modules/file/utils/generatePubObjectOptions.ts +++ b/apps/dcellar-web-ui/src/modules/file/utils/generatePubObjectOptions.ts @@ -16,7 +16,7 @@ export const makePutObjectHeaders = async ( authType: AuthType, ) => { const client = await getClient(); - const { bucketName, objectName, txnHash, body, duration = 30000 } = configParam; + const { bucketName, objectName, txnHash, body, endpoint } = configParam; if (!isValidBucketName(bucketName)) { throw new Error('Error bucket name'); } @@ -26,7 +26,6 @@ export const makePutObjectHeaders = async ( if (!txnHash) { throw new Error('Transaction hash is empty, please check.'); } - const endpoint = await client.sp.getSPUrlByBucket(bucketName); const method = METHOD_PUT; const params = new URLSearchParams(); const payload = { diff --git a/apps/dcellar-web-ui/src/modules/object/index.tsx b/apps/dcellar-web-ui/src/modules/object/index.tsx index 21aaf4d9..86e9da52 100644 --- a/apps/dcellar-web-ui/src/modules/object/index.tsx +++ b/apps/dcellar-web-ui/src/modules/object/index.tsx @@ -14,18 +14,16 @@ import { import { ObjectBreadcrumb } from '@/modules/object/components/ObjectBreadcrumb'; import { dropRight, last } from 'lodash-es'; import { NewObject } from '@/modules/object/components/NewObject'; -import { Tooltip, Flex } from '@totejs/uikit'; +import { Flex, Tooltip } from '@totejs/uikit'; import { setFolders } from '@/store/slices/object'; import { ObjectList } from '@/modules/object/components/ObjectList'; import React, { useEffect } from 'react'; -import { SpItem, setPrimarySpInfo } from '@/store/slices/sp'; -import { getVirtualGroupFamily } from '@/facade/virtual-group'; +import { getPrimarySpInfo } from '@/store/slices/sp'; import { ForwardIcon } from '@totejs/icons'; import { setupAccountsInfo } from '@/store/slices/accounts'; export const ObjectsPage = () => { const dispatch = useAppDispatch(); - const { allSps, primarySpInfo } = useAppSelector((root) => root.sp); const { bucketInfo } = useAppSelector((root) => root.bucket); const { loginAccount } = useAppSelector((root) => root.persist); const selectedRowKeys = useAppSelector((root) => root.object.selectedRowKeys); @@ -34,6 +32,7 @@ export const ObjectsPage = () => { const items = path as string[]; const title = last(items)!; const [bucketName, ...folders] = items; + const bucket = bucketInfo[bucketName]; useEffect(() => { dispatch(setFolders({ bucketName, folders })); @@ -43,22 +42,12 @@ export const ObjectsPage = () => { }, [bucketName, dispatch, folders]); useAsyncEffect(async () => { - const bucket = bucketInfo[bucketName]; if (!bucket) return; - const primarySp = primarySpInfo[bucketName]; // 1. set global primary sp info - if (!primarySp) { - const [data, error] = await getVirtualGroupFamily({ - familyId: +bucket.GlobalVirtualGroupFamilyId, - }); - const sp = allSps.find( - (item) => item.id === data?.globalVirtualGroupFamily?.primarySpId, - ) as SpItem; - dispatch(setPrimarySpInfo({ bucketName, sp })); - } + dispatch(getPrimarySpInfo(bucketName, +bucket.GlobalVirtualGroupFamilyId)); // 2. set payment account infos - dispatch(setupAccountsInfo(bucket.PaymentAddress)) - }, [bucketInfo, bucketName]); + dispatch(setupAccountsInfo(bucket.PaymentAddress)); + }, [bucket, bucketName]); useAsyncEffect(async () => { const bucket = bucketInfo[bucketName]; diff --git a/apps/dcellar-web-ui/src/modules/share/SharedFile.tsx b/apps/dcellar-web-ui/src/modules/share/SharedFile.tsx index 48c162e4..2d79e3aa 100644 --- a/apps/dcellar-web-ui/src/modules/share/SharedFile.tsx +++ b/apps/dcellar-web-ui/src/modules/share/SharedFile.tsx @@ -15,20 +15,13 @@ import { previewObject, } from '@/facade/object'; import { quotaRemains } from '@/facade/bucket'; -import { - E_NO_QUOTA, - E_OFF_CHAIN_AUTH, - E_PERMISSION_DENIED, - E_SP_NOT_FOUND, - E_UNKNOWN, -} from '@/facade/error'; +import { E_NO_QUOTA, E_OFF_CHAIN_AUTH, E_PERMISSION_DENIED, E_UNKNOWN } from '@/facade/error'; import { reportEvent } from '@/utils/reportEvent'; import { Loading } from '@/components/common/Loading'; -import { useAppDispatch, useAppSelector } from '@/store'; +import { useAppDispatch } from '@/store'; import { getSpOffChainData } from '@/store/slices/persist'; import { setupBucketQuota } from '@/store/slices/bucket'; import { useOffChainAuth } from '@/hooks/useOffChainAuth'; -import { getSpUrlByBucketName } from '@/facade/virtual-group'; import { SpItem } from '@/store/slices/sp'; import { VisibilityType } from '../file/type'; import { PermissionTypes } from '@bnb-chain/greenfield-js-sdk'; @@ -38,6 +31,7 @@ interface SharedFileProps { objectInfo: ObjectInfo; quotaData: IQuotaProps; loginAccount: string; + primarySp: SpItem; } type ActionType = 'view' | 'download' | ''; @@ -47,9 +41,9 @@ export const SharedFile = memo(function SharedFile({ objectInfo, quotaData, loginAccount, + primarySp, }) { const dispatch = useAppDispatch(); - const { allSps } = useAppSelector((root) => root.sp); const [action, setAction] = useState(''); const [statusModalIcon, setStatusModalIcon] = useState(''); const [statusModalTitle, setStatusModalTitle] = useState(''); @@ -89,12 +83,6 @@ export const SharedFile = memo(function SharedFile({ if (!remainQuota) return onError(E_NO_QUOTA); setAction(e); - const [primarySpEndpoint, error] = await getSpUrlByBucketName(bucketName); - if (!primarySpEndpoint) { - return error; - } - const primarySp = allSps.find((item: SpItem) => item.endpoint === primarySpEndpoint); - if (!primarySp) return onError(E_SP_NOT_FOUND); const operator = primarySp.operatorAddress; const { seedString } = await dispatch(getSpOffChainData(loginAccount, operator)); const isPrivate = objectInfo.visibility === VisibilityType.VISIBILITY_TYPE_PRIVATE; @@ -103,7 +91,7 @@ export const SharedFile = memo(function SharedFile({ const [_, accessError] = await getCanObjectAccess( bucketName, objectName, - primarySpEndpoint, + primarySp.endpoint, loginAccount, seedString, ); diff --git a/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx b/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx index 1e72a133..e89065e2 100644 --- a/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx +++ b/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx @@ -92,7 +92,7 @@ export const UploadObjects = memo(function UploadObjects() { const { tabOptions, activeKey, setActiveKey } = useUploadTab(); const { PaymentAddress } = bucketInfo[bucketName] || {}; - console.log('bucketInfo[bucketName]', bucketInfo[bucketName]) + console.log('bucketInfo[bucketName]', bucketInfo[bucketName]); const onClose = () => { dispatch(setEditUploadStatus(false)); dispatch(setEditUpload({} as TEditUpload)); @@ -240,8 +240,8 @@ export const UploadObjects = memo(function UploadObjects() { Upload Objects - {!isEmpty(selectedFiles) && ( - + + {!isEmpty(selectedFiles) && ( setActiveKey(key)}> {tabOptions.map((item) => ( @@ -265,8 +265,8 @@ export const UploadObjects = memo(function UploadObjects() { ))} - - )} + )} + = (props) => { const { loginAccount } = useAppSelector((root) => root.persist); const dispatch = useAppDispatch(); const [getPermission, setGetPermission] = useState(true); + const [primarySp, setPrimarySp] = useState({} as SpItem); useAsyncEffect(async () => { if (!oneSp) return; const { seedString } = await dispatch(getSpOffChainData(loginAccount, oneSp)); - const [primarySpEndpoint, error] = await getSpUrlByBucketName(bucketName); - if (!primarySpEndpoint) { + const bucketInfo = await headBucket(bucketName); + if (!bucketInfo) { // bucket not exist setObjectInfo(null); setQuotaData(null); return; } + const sp = await dispatch(getPrimarySpInfo(bucketName, +bucketInfo.globalVirtualGroupFamilyId)); + if (!sp) { + // bucket not exist + setObjectInfo(null); + setQuotaData(null); + return; + } + setPrimarySp(sp); const params = { bucketName, objectName, - endpoint: primarySpEndpoint, + endpoint: sp.endpoint, seedString, address: loginAccount, }; @@ -129,6 +139,7 @@ const SharePage: NextPage = (props) => { ) : ( & { }; export type TEditDetailItem = BucketItem & { PrimarySpAddress?: string }; + export interface BucketState { bucketInfo: Record; buckets: Record; @@ -162,19 +162,11 @@ export const setupBuckets = export const setupBucketQuota = (bucketName: string) => async (dispatch: AppDispatch, getState: GetState) => { - const { allSps } = getState().sp; const { loginAccount } = getState().persist; const { bucketInfo } = getState().bucket; const info = bucketInfo[bucketName]; if (!info) return; - const familyId = bucketInfo[bucketName].GlobalVirtualGroupFamilyId; - const [familyResp, VGerror] = await getVirtualGroupFamily({ familyId: +familyId }); - if (familyResp === null) { - return VGerror; - } - const sp = allSps.find( - (item: SpItem) => item.id === familyResp.globalVirtualGroupFamily?.primarySpId, - ); + const sp = await dispatch(getPrimarySpInfo(bucketName, +info.GlobalVirtualGroupFamilyId)); if (!sp) return; const { seedString } = await dispatch(getSpOffChainData(loginAccount, sp.operatorAddress)); const [quota, error] = await getBucketReadQuota({ diff --git a/apps/dcellar-web-ui/src/store/slices/sp.ts b/apps/dcellar-web-ui/src/store/slices/sp.ts index 5078d287..1d3b8ace 100644 --- a/apps/dcellar-web-ui/src/store/slices/sp.ts +++ b/apps/dcellar-web-ui/src/store/slices/sp.ts @@ -6,6 +6,7 @@ import { } from '@bnb-chain/greenfield-cosmos-types/greenfield/sp/types'; import { AppDispatch, GetState } from '@/store'; import { find, omit, random, sortBy } from 'lodash-es'; +import { getVirtualGroupFamily } from '@/facade/virtual-group'; const defaultDescription = (): Description => ({ moniker: '', @@ -90,8 +91,8 @@ export const spSlice = createSlice({ state.oneSp = !len ? '' : state.sps[random(0, len - 1)]?.operatorAddress; } }, - setPrimarySpInfo(state, { payload }: PayloadAction<{bucketName: string, sp: SpItem}>) { - const {bucketName, sp} = payload; + setPrimarySpInfo(state, { payload }: PayloadAction<{ bucketName: string; sp: SpItem }>) { + const { bucketName, sp } = payload; state.primarySpInfo[bucketName] = sp; }, updateSps(state, { payload }: PayloadAction) { @@ -106,7 +107,8 @@ export const spSlice = createSlice({ }, }); -export const { setStorageProviders, setPrimarySpInfo, updateSps, filterSps, setSpMeta } = spSlice.actions; +export const { setStorageProviders, setPrimarySpInfo, updateSps, filterSps, setSpMeta } = + spSlice.actions; export const setupStorageProviders = () => async (dispatch: AppDispatch, getState: GetState) => { const { sps: _sps } = getState().sp; @@ -127,4 +129,19 @@ export const setupSpMeta = () => async (dispatch: AppDispatch) => { dispatch(setSpMeta(list || [])); }; +export const getPrimarySpInfo = + (bucketName: string, familyId: number) => async (dispatch: AppDispatch, getState: GetState) => { + const { allSps, primarySpInfo } = getState().sp; + const primarySp = primarySpInfo[bucketName]; + if (primarySp) return primarySp; + const [data, error] = await getVirtualGroupFamily({ familyId }); + if (error) return null; + const sp = allSps.find( + (item) => item.id === data?.globalVirtualGroupFamily?.primarySpId, + ) as SpItem; + if (!sp) return null; + dispatch(setPrimarySpInfo({ bucketName, sp })); + return sp; + }; + export default spSlice.reducer;