Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dcellar-web-ui): introduce the stop upload feature #385

Merged
merged 11 commits into from
May 16, 2024
Merged
1 change: 1 addition & 0 deletions apps/dcellar-web-ui/public/js/iconfont_v0.1.12.min.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ export const GlobalObjectUploadManager = memo<GlobalTasksProps>(
} else {
axios
.put(url, task.waitObject.file, {
signal: task.abortController?.signal,
async onUploadProgress(progressEvent) {
const progress = progressEvent.total
? Math.floor((progressEvent.loaded / progressEvent.total) * 100)
Expand Down Expand Up @@ -265,6 +266,7 @@ export const GlobalObjectUploadManager = memo<GlobalTasksProps>(
setupUploadTaskErrorMsg({
account: loginAccount,
task,
status: e?.code === 'ERR_CANCELED' ? 'CANCEL' : 'ERROR',
errorMsg: authExpired
? 'Authentication expired.'
: message || e?.message || 'upload error',
Expand Down Expand Up @@ -461,8 +463,28 @@ export const GlobalObjectUploadManager = memo<GlobalTasksProps>(
// 3. upload
useAsyncEffect(async () => {
if (!uploadTasks.length) return;
dispatch(updateUploadStatus({ ids: uploadTasks, status: 'UPLOAD', account: loginAccount }));
const tasks = queue.filter((t) => uploadTasks.includes(t.id));
// Add abortController to each task
const extraFields: Record<string, Partial<UploadObject>> = uploadTasks.reduce(
(acc, id) => {
acc[id] = {
abortController: new AbortController(),
};
return acc;
},
{} as Record<string, Partial<UploadObject>>,
);
dispatch(
updateUploadStatus({
ids: uploadTasks,
status: 'UPLOAD',
account: loginAccount,
extraFields,
}),
);

const tasks = queue
.filter((t) => uploadTasks.includes(t.id))
.map((t) => ({ ...t, ...extraFields[t.id] }));
tasks.forEach(runUploadTask);
}, [uploadTasks.join('')]);

Expand Down
14 changes: 9 additions & 5 deletions apps/dcellar-web-ui/src/modules/upload/ObjectUploadStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { UploadObject } from '@/store/slices/global';
import { Text } from '@node-real/uikit';
import { Loading } from '@/components/common/Loading';
import { UploadProgress } from './UploadProgress';
import { IconFont } from '@/components/IconFont';
import { memo } from 'react';

export const ObjectUploadStatus = ({ task }: { task: UploadObject }) => {
export const ObjectUploadStatus = memo(function ObjectUploadStatus({
task,
}: {
task: UploadObject;
}) {
switch (task.status) {
case 'RETRY_CHECK':
case 'RETRY_CHECKING':
Expand Down Expand Up @@ -61,11 +65,11 @@ export const ObjectUploadStatus = ({ task }: { task: UploadObject }) => {
case 'CANCEL':
return (
<>
<IconFont type="colored-error2" w={20} />
Cancelled
<IconFont type="stop" w={20} />
Stopped
</>
);
default:
return null;
}
};
});
65 changes: 52 additions & 13 deletions apps/dcellar-web-ui/src/modules/upload/UploadActionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,58 @@
import { IconFont } from '@/components/IconFont';
import { DCButton } from '@/components/common/DCButton';
import { useAppDispatch, useAppSelector } from '@/store';
import { clearUploadRecords, retryUploadTasks } from '@/store/slices/global';
import {
cancelUploadingRequests,
clearUploadRecords,
retryUploadTasks,
updateUploadStatus,
} from '@/store/slices/global';
<<<<<<< HEAD
<<<<<<< HEAD
import React, { useCallback } from 'react';
=======
=======
>>>>>>> f143b09b (feat(dcellar-web-ui): introduce the stop upload feature)
import React from 'react';
>>>>>>> 2ee2f675 (feat(dcellar-web-ui): introduce the stop upload feature)

export type ActionButtonProps = {
type: 'clear' | 'retry' | 'clear-all' | 'retry-all';
type: 'clear' | 'retry' | 'clear-all' | 'retry-all' | 'cancel' | 'cancel-all';
ids: number[];
text?: string;
};

const actionItems = [
{
type: 'clear',
text: 'Clear',
icon: 'delete',
type: 'cancel',
text: 'Cancel',
icon: 'stop',
},
{
type: 'cancel-all',
text: 'Stop Uploading',
icon: 'stop',
},
{
type: 'retry',
text: 'Retry',
icon: 'retry',
},
{
type: 'clear-all',
text: 'Clear All Records',
icon: 'delete',
},
{
type: 'retry-all',
text: 'Retry All',
icon: 'retry',
},
{
type: 'clear',
text: 'Clear',
icon: 'delete',
},
{
type: 'clear-all',
text: 'Clear All Records',
icon: 'delete',
},
];

export const UploadActionButton = React.memo(function UploadActionButton({
Expand All @@ -42,6 +64,19 @@ export const UploadActionButton = React.memo(function UploadActionButton({
const dispatch = useAppDispatch();
const actionItem = actionItems.find((item) => item.type === type);

const onCancel = useCallback(
(ids: number[]) => {
dispatch(
updateUploadStatus({
account: loginAccount,
ids,
status: 'CANCEL',
}),
);
dispatch(cancelUploadingRequests({ ids }));
},
[dispatch, loginAccount],
);
const onClear = (ids: number[]) => {
dispatch(clearUploadRecords({ ids, loginAccount }));
};
Expand All @@ -50,14 +85,18 @@ export const UploadActionButton = React.memo(function UploadActionButton({
};
const onClick = () => {
switch (type) {
case 'clear':
case 'clear-all':
onClear(ids);
case 'cancel':
case 'cancel-all':
onCancel(ids);
break;
case 'retry':
case 'retry-all':
onRetry(ids);
break;
case 'clear':
case 'clear-all':
onClear(ids);
break;
default:
break;
}
Expand Down
15 changes: 10 additions & 5 deletions apps/dcellar-web-ui/src/modules/upload/UploadingObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { UploadingPanelKey, useTaskManagementTab } from './useTaskManagementTab'

import { IconFont } from '@/components/IconFont';
import { UploadingObjectsList } from './UploadingObjectsList';
import { UploadObject } from '@/store/slices/global';
import { UPLOADING_STATUSES, UPLOAD_FAILED_STATUSES, UploadObject } from '@/store/slices/global';
import { UploadActionButton } from './UploadActionButton';

interface UploadingObjectsProps {}
Expand All @@ -36,15 +36,20 @@ export const UploadingObjects = memo<UploadingObjectsProps>(function UploadingOb
panelKey: UploadingPanelKey;
data: UploadObject[];
}) => {
if ([UploadingPanelKey.ALL, UploadingPanelKey.UPLOADING].includes(panelKey)) {
return null;
}
return (
<Flex mb={12}>
{panelKey === UploadingPanelKey.COMPLETE && (
<UploadActionButton type="clear-all" ids={data.map((item) => item.id)} />
)}
{panelKey === UploadingPanelKey.FAILED && (
{(panelKey === UploadingPanelKey.UPLOADING || panelKey === UploadingPanelKey.ALL) && (
<UploadActionButton
type="cancel-all"
ids={data
.filter((item) => UPLOADING_STATUSES.includes(item.status))
.map((item) => item.id)}
/>
)}
{(panelKey === UploadingPanelKey.FAILED || panelKey === UploadingPanelKey.STOPPED) && (
<Flex gap={6}>
<UploadActionButton type="retry-all" ids={data.map((item) => item.id)} />
<UploadActionButton type="clear-all" ids={data.map((item) => item.id)} />
Expand Down
43 changes: 26 additions & 17 deletions apps/dcellar-web-ui/src/modules/upload/UploadingObjectsList.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { DCTable } from '@/components/common/DCTable';
import {
UPLOADING_STATUSES,
UPLOAD_FAILED_STATUSES,
UPLOAD_SUCCESS_STATUS,
UploadObject,
} from '@/store/slices/global';
import { UploadObject } from '@/store/slices/global';
import { ColumnProps } from 'antd/es/table';
import React, { useState } from 'react';
import { NameItem } from './NameItem';
Expand Down Expand Up @@ -34,7 +29,6 @@ export const UploadingObjectsList = ({ data }: { data: UploadObject[] }) => {
size={record.waitObject.size}
msg={record.msg}
status={record.status}
w={234}
task={record}
/>
);
Expand Down Expand Up @@ -72,23 +66,38 @@ export const UploadingObjectsList = ({ data }: { data: UploadObject[] }) => {
title: 'Action',
width: 146,
render: (record) => {
if (UPLOADING_STATUSES.includes(record.status)) {
const { status, id } = record;
if (['SEAL', 'SEALING'].includes(status)) {
return (
<Text color="readable.disable" fontSize={12}>
--
</Text>
);
}

if (UPLOAD_SUCCESS_STATUS === record.status) {
return <UploadActionButton type="clear" text="Clear Record" ids={[record.id]} />;
} else if (UPLOAD_FAILED_STATUSES.includes(record.status)) {
return (
<Flex gap={6}>
<UploadActionButton type="retry" ids={[record.id]} />
<UploadActionButton type="clear" ids={[record.id]} />
</Flex>
);
switch (status) {
case 'FINISH':
return <UploadActionButton type="clear" text="Clear Record" ids={[id]} />;

case 'CANCEL':
case 'ERROR':
return (
<Flex gap={6}>
<UploadActionButton type="retry" ids={[id]} />
<UploadActionButton type="clear" ids={[id]} />
</Flex>
);

case 'WAIT':
case 'HASH':
case 'HASHED':
case 'SIGN':
case 'SIGNED':
case 'UPLOAD':
return <UploadActionButton type="cancel" text="Cancel" ids={[id]} />;

default:
return null;
}
},
},
Expand Down
22 changes: 14 additions & 8 deletions apps/dcellar-web-ui/src/modules/upload/useTaskManagementTab.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { useAppSelector } from '@/store';
import { UploadObject } from '@/store/slices/global';
import { UPLOADING_STATUSES, UploadObject } from '@/store/slices/global';

import { sortBy } from 'lodash-es';
import { useMemo, useState } from 'react';

export enum UploadingPanelKey {
ALL = 'ALL',
UPLOADING = 'HASH-UPLOAD-SEAL',
UPLOADING = 'RETRY-WAIT-HASH-UPLOAD-SIGN-SEAL',
STOPPED = 'CANCEL',
COMPLETE = 'FINISH',
FAILED = 'ERROR-CANCEL',
FAILED = 'ERROR',
}

export const useTaskManagementTab = () => {
Expand All @@ -17,14 +18,14 @@ export const useTaskManagementTab = () => {

const queue = sortBy(objectUploadQueue[loginAccount] || [], (o) => o.waitObject.time);

const { uploadingQueue, completeQueue, errorQueue } = useMemo(() => {
const uploadingQueue = queue?.filter((i) =>
['HASH', 'UPLOAD', 'SEAL', 'SEALING'].includes(i.status),
);
const { uploadingQueue, stoppedQueue, completeQueue, errorQueue } = useMemo(() => {
const uploadingQueue = queue?.filter((i) => UPLOADING_STATUSES.includes(i.status));
const completeQueue = queue?.filter((i) => i.status === 'FINISH');
const errorQueue = queue?.filter((i) => ['ERROR', 'CANCEL'].includes(i.status));
const stoppedQueue = queue?.filter((i) => i.status === 'CANCEL');
const errorQueue = queue?.filter((i) => ['ERROR'].includes(i.status));
return {
uploadingQueue,
stoppedQueue,
completeQueue,
errorQueue,
};
Expand All @@ -46,6 +47,11 @@ export const useTaskManagementTab = () => {
key: UploadingPanelKey.UPLOADING,
data: uploadingQueue,
},
{
title: 'Stopped',
key: UploadingPanelKey.STOPPED,
data: stoppedQueue,
},
{
title: 'Complete',
key: UploadingPanelKey.COMPLETE,
Expand Down
2 changes: 1 addition & 1 deletion apps/dcellar-web-ui/src/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function Document() {
__html: `window.__ASSET_PREFIX = ${flatted.stringify(assetPrefix)}`,
}}
></script>
<script defer src={`${assetPrefix}/js/iconfont_v0.1.2.min.js`}></script>
<script defer src={`${assetPrefix}/js/iconfont_v0.1.12.min.js`}></script>
<script defer src={`${assetPrefix}/wasm/tinygo_wasm_exec_v1.js`}></script>
<script defer src={`${assetPrefix}/wasm/tinygo_init_v1.js`}></script>
<EthereumScript />
Expand Down
Loading
Loading