diff --git a/apps/dcellar-web-ui/src/components/common/DCTable/index.tsx b/apps/dcellar-web-ui/src/components/common/DCTable/index.tsx
index 65704fe7..824efabd 100644
--- a/apps/dcellar-web-ui/src/components/common/DCTable/index.tsx
+++ b/apps/dcellar-web-ui/src/components/common/DCTable/index.tsx
@@ -70,12 +70,27 @@ export const SealLoading = () => {
}
`;
return (
-
+
+
+
+
+
+ Sealing...
+
+
);
};
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 8859ed05..f77ed80e 100644
--- a/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx
+++ b/apps/dcellar-web-ui/src/components/layout/Header/GlobalTasks.tsx
@@ -24,6 +24,7 @@ import { genCreateObjectTx } from '@/modules/file/utils/genCreateObjectTx';
import { resolve } from '@/facade/common';
import { broadcastFault, commonFault, createTxFault, simulateFault } from '@/facade/error';
import { isEmpty } from 'lodash-es';
+import { parseErrorXml } from '@/utils/common';
interface GlobalTasksProps {}
@@ -159,12 +160,12 @@ export const GlobalTasks = memo(function GlobalTasks() {
'X-Gnfd-User-Address': headers.get('X-Gnfd-User-Address'),
'X-Gnfd-App-Domain': headers.get('X-Gnfd-App-Domain'),
},
- }).catch(e => {
- console.log('upload error', e);
+ }).catch(async (e: Response) => {
+ const {code, message} = await parseErrorXml(e)
dispatch(updateUploadTaskMsg({
account: loginAccount,
id: task.id,
- msg: e?.message || 'Upload error',
+ msg: message || 'Upload error',
}));
})
};
diff --git a/apps/dcellar-web-ui/src/facade/account.ts b/apps/dcellar-web-ui/src/facade/account.ts
index b4181370..72345e8d 100644
--- a/apps/dcellar-web-ui/src/facade/account.ts
+++ b/apps/dcellar-web-ui/src/facade/account.ts
@@ -51,6 +51,7 @@ export const createTmpAccount = async ({
// 2. allow temporary account to submit specified tx and amount
const client = await getClient();
+ // MsgGrantAllowanceTypeUrl
const grantAllowanceTx = await client.feegrant.grantAllowance({
granter: address,
grantee: wallet.address,
diff --git a/apps/dcellar-web-ui/src/modules/upload/SimulateFee.tsx b/apps/dcellar-web-ui/src/modules/upload/SimulateFee.tsx
index 7ac7743c..55aae2cf 100644
--- a/apps/dcellar-web-ui/src/modules/upload/SimulateFee.tsx
+++ b/apps/dcellar-web-ui/src/modules/upload/SimulateFee.tsx
@@ -6,15 +6,14 @@ import {
renderPrelockedFeeValue,
} from '@/modules/file/utils';
import { useAppDispatch, useAppSelector } from '@/store';
-import { MsgCreateObjectTypeUrl } from '@bnb-chain/greenfield-chain-sdk';
-import { Box, Flex, Slide, Text, useDisclosure, Link } from '@totejs/uikit';
+import { MsgCreateObjectTypeUrl, MsgGrantAllowanceTypeUrl, MsgPutPolicyTypeUrl } from '@bnb-chain/greenfield-chain-sdk';
+import { Box, Flex, Text, useDisclosure, Link } from '@totejs/uikit';
import React, { useEffect, useMemo } from 'react';
import { useAsyncEffect, useMount } from 'ahooks';
import { WaitFile, setupPreLockFeeObjects, setupTmpAvailableBalance } from '@/store/slices/global';
import { isEmpty } from 'lodash-es';
import { calPreLockFee } from '@/utils/sp';
import { MenuCloseIcon } from '@totejs/icons';
-import { useUpdateEffect } from 'react-use';
import { setEditUpload } from '@/store/slices/object';
import BigNumber from 'bignumber.js';
import { DECIMAL_NUMBER } from '../wallet/constants';
@@ -39,8 +38,14 @@ export const Fee = () => {
}
}, [primarySp?.operatorAddress]);
- const lockFee = useMemo(() => {
+ const createTmpAccountGasFee = useMemo(() => {
+ const grantAllowTxFee = BigNumber(gasObjects[MsgGrantAllowanceTypeUrl].gasFee).plus(BigNumber(gasObjects[MsgGrantAllowanceTypeUrl].perItemFee).times(1));
+ const putPolicyTxFee = BigNumber(gasObjects[MsgPutPolicyTypeUrl].gasFee);
+
+ return grantAllowTxFee.plus(putPolicyTxFee).toString(DECIMAL_NUMBER);
+ }, [gasObjects]);
+ const lockFee = useMemo(() => {
if (!primarySp?.operatorAddress) return;
const preLockFeeObject = preLockFeeObjects[primarySp.operatorAddress];
if (isEmpty(preLockFeeObject) || isChecking) {
@@ -63,7 +68,7 @@ export const Fee = () => {
const gasFee = isChecking
? -1
- : waitQueue.filter((item: WaitFile) => item.status !== 'ERROR').length * singleTxGasFee;
+ : BigNumber(waitQueue.filter((item: WaitFile) => item.status !== 'ERROR').length).times(singleTxGasFee).plus(BigNumber(createTmpAccountGasFee).toString(DECIMAL_NUMBER)).toString(DECIMAL_NUMBER);
useEffect(() => {
if (gasFee && lockFee) {
diff --git a/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx b/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx
index 1d63e260..a8b6d0ec 100644
--- a/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx
+++ b/apps/dcellar-web-ui/src/modules/upload/UploadObjects.tsx
@@ -120,16 +120,18 @@ export const UploadObjects = memo(function UploadObjects() {
if (file.name.includes('//')) {
return E_OBJECT_NAME_CONTAINS_SLASH;
}
- const objectListNames = objectList.map((item) => item.name);
- const uploadingNames = (uploadQueue?.[loginAccount] || [])
+ // Validation only works to data within the current path.
+ const objectListObjectNames = objectList.map((item) => bucketName + '/' + item.objectName);
+ // Avoid add same file to the uploading queue.
+ const uploadingObjectNames = (uploadQueue?.[loginAccount] || [])
+ .filter((item) => ['WAIT', 'HASH', 'READY', 'UPLOAD', 'SEAL'].includes(item.status))
.map((item) => {
- const curPrefix = [bucketName, ...folders].join('/');
- const filePrefix = [item.bucketName, ...item.prefixFolders].join('/');
- return curPrefix === filePrefix ? item.file.name : '';
- })
- .filter((item) => item);
- const isExistObjectList = objectListNames.includes(file.name);
- const isExistUploadList = uploadingNames.includes(file.name);
+ return [item.bucketName, ...item.prefixFolders, item.file.name].join('/');
+ });
+ const fullObjectName = [path, file.name].join('/');
+ const isExistObjectList = objectListObjectNames.includes(fullObjectName);
+ const isExistUploadList = uploadingObjectNames.includes(fullObjectName);
+
if (isExistObjectList || isExistUploadList) {
return E_OBJECT_NAME_EXISTS;
}
@@ -207,7 +209,6 @@ export const UploadObjects = memo(function UploadObjects() {
}, [preLockFeeObjects, selectedFiles]);
const checkedQueue = selectedFiles.filter((item) => item.status === 'WAIT');
- // console.log(loading, creating, !checkedQueue?.length, !editUpload.isBalanceAvailable, editUpload);
return (
diff --git a/apps/dcellar-web-ui/src/store/slices/global.ts b/apps/dcellar-web-ui/src/store/slices/global.ts
index 8c92855d..cae2f20d 100644
--- a/apps/dcellar-web-ui/src/store/slices/global.ts
+++ b/apps/dcellar-web-ui/src/store/slices/global.ts
@@ -9,12 +9,14 @@ import { getSpOffChainData } from '@/store/slices/persist';
import { defaultBalance } from '@/store/slices/balance';
import Long from 'long';
import { VisibilityType } from '@bnb-chain/greenfield-cosmos-types/greenfield/storage/common';
+import { MsgGrantAllowanceTypeUrl } from '@bnb-chain/greenfield-chain-sdk';
export type TGasList = {
[msgTypeUrl: string]: {
gasLimit: number;
msgTypeUrl: string;
gasFee: number;
+ perItemFee: number;
};
};
@@ -201,12 +203,20 @@ export const globalSlice = createSlice({
const { gasPrice } = state.gasHub;
const gasObjects = keyBy(
payload.msgGasParams.map((item) => {
- const gasLimit = item.fixedType?.fixedGas.low || 0;
- const gasFee = gasPrice * gasLimit;
+ let gasLimit = item.fixedType?.fixedGas.low || 0;
+ let gasFee = gasPrice * gasLimit;
+ let perItemFee = 0;
+ if (item.msgTypeUrl === MsgGrantAllowanceTypeUrl) {
+ gasLimit = item.grantAllowanceType?.fixedGas.low || 0;
+ gasFee = gasPrice * gasLimit;
+ perItemFee = (item.grantAllowanceType?.gasPerItem.low || 0) * gasPrice;
+ }
+
return {
msgTypeUrl: item.msgTypeUrl,
gasLimit,
gasFee,
+ perItemFee,
};
}),
'msgTypeUrl',
diff --git a/apps/dcellar-web-ui/src/utils/common/index.tsx b/apps/dcellar-web-ui/src/utils/common/index.tsx
new file mode 100644
index 00000000..7b20adbe
--- /dev/null
+++ b/apps/dcellar-web-ui/src/utils/common/index.tsx
@@ -0,0 +1,17 @@
+export const parseErrorXml = async (result: Response) => {
+ try {
+ const xmlText = await result.text();
+ const xml = await new window.DOMParser().parseFromString(xmlText, 'text/xml');
+ const code = (xml as XMLDocument).getElementsByTagName('Code')[0].textContent;
+ const message = (xml as XMLDocument).getElementsByTagName('Message')[0].textContent;
+ return {
+ code,
+ message,
+ };
+ } catch {
+ return {
+ code: null,
+ message: null,
+ };
+ }
+};
\ No newline at end of file