@zjlab-fe/data-hub-ui 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +1 -1
  2. package/dist/types/components/file-uploader/components/icons.d.ts +1 -0
  3. package/dist/types/components/file-uploader/components/uploader-file-item.d.ts +4 -0
  4. package/dist/types/components/file-uploader/components/uploader-progress-bar.d.ts +9 -0
  5. package/dist/types/components/file-uploader/components/uploader.d.ts +2 -0
  6. package/dist/types/components/file-uploader/context/use-upload-engine.d.ts +5 -0
  7. package/dist/types/components/file-uploader/demo/index.d.ts +1 -0
  8. package/dist/types/components/file-uploader/demo/mockApi.d.ts +37 -0
  9. package/dist/types/components/file-uploader/hooks/use-upload.d.ts +4 -0
  10. package/dist/types/components/file-uploader/index.d.ts +1 -0
  11. package/dist/types/components/file-uploader/types.d.ts +5 -0
  12. package/dist/types/components/limit-credit-modal/demo/index.d.ts +3 -0
  13. package/dist/types/components/limit-credit-modal/index.d.ts +9 -0
  14. package/dist/types/index.d.ts +2 -0
  15. package/es/components/file-uploader/components/icons.js +7 -4
  16. package/es/components/file-uploader/components/uploader-file-item.css.js +22 -0
  17. package/es/components/file-uploader/components/uploader-file-item.js +4 -3
  18. package/es/components/file-uploader/components/uploader-progress-bar.css.js +43 -0
  19. package/es/components/file-uploader/components/uploader-progress-bar.js +19 -0
  20. package/es/components/file-uploader/components/uploader.js +4 -3
  21. package/es/components/file-uploader/context/use-upload-engine.js +108 -131
  22. package/es/components/file-uploader/hooks/use-upload.js +15 -1
  23. package/es/components/file-uploader/utils/upload-controllers.js +43 -1
  24. package/es/components/limit-credit-modal/index.js +36 -0
  25. package/es/components/test-component/index.js +9 -0
  26. package/es/components/test-component/index.scss.js +7 -0
  27. package/es/index.js +2 -0
  28. package/lib/index.js +1 -1
  29. package/package.json +3 -2
@@ -5,7 +5,7 @@ import { UploadStatus } from '../constants.js';
5
5
  import { createUploadError, UPLOAD_ERROR_CODE, parseError } from '../utils/error-handler.js';
6
6
  import { handlerRegistry } from './handler-registry.js';
7
7
  import { actionRegistry } from './action-registry.js';
8
- import { resetInterruptedChunks, getChunksForResume } from '../utils/upload-controllers.js';
8
+ import { resetInterruptedChunks, getChunksForResume, getFailedChunks, resetFailedChunks, resetAllChunks } from '../utils/upload-controllers.js';
9
9
  import { fileStateStore } from './file-state-store.js';
10
10
  import { ensureHandlers } from '../utils/ensure-handlers.js';
11
11
 
@@ -25,6 +25,7 @@ function getHandlerContext() {
25
25
  pause: () => { },
26
26
  resume: () => __awaiter(this, void 0, void 0, function* () { }),
27
27
  cancel: () => { },
28
+ retry: () => __awaiter(this, void 0, void 0, function* () { return ({ success: false, retryType: 'smart' }); }),
28
29
  getFileById: () => undefined,
29
30
  };
30
31
  }
@@ -291,135 +292,111 @@ function useUploadEngine() {
291
292
  * @param forceFullRetry - Skip smart retry and do full retry immediately
292
293
  * @returns Object with success status and retry type used
293
294
  */
294
- // const retryUpload = useCallback(
295
- // async (
296
- // fileId: string,
297
- // forceFullRetry: boolean = false,
298
- // ): Promise<{ success: boolean; retryType: 'smart' | 'full' }> => {
299
- // const file = stateRef.current.files.find((f) => f.id === fileId);
300
- // if (!file || !file.file) {
301
- // const error = createUploadError(UPLOAD_ERROR_CODE.MISSING_FILE, 'File is missing, cannot retry');
302
- // console.error(error.message);
303
- // return { success: false, retryType: 'smart' };
304
- // }
305
- // const h = ensureHandlers(fileId, file);
306
- // if (!h) {
307
- // return { success: false, retryType: 'smart' };
308
- // }
309
- // // Increment retry count
310
- // const retryCount = (file.retryCount ?? 0) + 1;
311
- // const failedChunksResult = getFailedChunks(file);
312
- // // If forcing full retry or no failed chunks, do full retry
313
- // if (forceFullRetry || !failedChunksResult.hasFailed) {
314
- // return performFullRetry(file, h, retryCount);
315
- // }
316
- // // ─────────────────────────────────────────────────────────────────────────
317
- // // SMART RETRY: Retry only failed chunks
318
- // // ─────────────────────────────────────────────────────────────────────────
319
- // try {
320
- // // Reset only failed chunks to pending
321
- // const updatedChunks = resetFailedChunks(file.chunks);
322
- // dispatch({
323
- // type: 'UPDATE_FILE',
324
- // id: fileId,
325
- // updates: {
326
- // status: UploadStatus.UPLOADING,
327
- // chunks: updatedChunks,
328
- // error: undefined,
329
- // errorCode: undefined,
330
- // retryCount,
331
- // },
332
- // });
333
- // // Get fresh URLs for all chunks (server needs full chunk count)
334
- // const urlResult = await h.onGetUploadUrls(file.fileName, file.chunks.length);
335
- // if (!urlResult.status) {
336
- // // URL request failed - try full retry as fallback
337
- // console.warn('Smart retry URL fetch failed, falling back to full retry');
338
- // return performFullRetry(file, h, retryCount);
339
- // }
340
- // // Filter URLs to only failed chunks
341
- // const failedUrls = filterUrlsForPendingChunks(
342
- // urlResult.uploadInfo.uploadUrls,
343
- // failedChunksResult.failedPartNums,
344
- // );
345
- // // Re-register handlers for background upload support
346
- // handlerRegistry.register(fileId, h, 'retryUpload:smart');
347
- // // Clear stale queue items and re-add with failed chunks only
348
- // const qm = getQueueManager();
349
- // qm.clearFileFromQueue(fileId);
350
- // const fileWithUrls = {
351
- // ...file,
352
- // uploadId: urlResult.uploadInfo.uploadId,
353
- // chunks: updatedChunks,
354
- // retryCount,
355
- // };
356
- // qm.addFile(fileWithUrls, failedUrls);
357
- // h.onRetry?.(file, 'smart');
358
- // return { success: true, retryType: 'smart' };
359
- // } catch (error) {
360
- // // Smart retry failed - fallback to full retry
361
- // const uploadError = parseError(error, 'Smart retry failed');
362
- // console.warn('Smart retry failed, falling back to full retry:', uploadError.message);
363
- // return performFullRetry(file, h, retryCount);
364
- // }
365
- // // ─────────────────────────────────────────────────────────────────────────
366
- // // FULL RETRY: Reset all chunks and start from beginning
367
- // // ─────────────────────────────────────────────────────────────────────────
368
- // async function performFullRetry(
369
- // uploadFile: UploadFile,
370
- // handlers: UploadHandlers,
371
- // retryAttempt: number,
372
- // ): Promise<{ success: boolean; retryType: 'full' }> {
373
- // try {
374
- // // Reset all chunks to pending
375
- // const resetChunks = resetAllChunks(uploadFile.chunks);
376
- // dispatch({
377
- // type: 'UPDATE_FILE',
378
- // id: fileId,
379
- // updates: {
380
- // status: UploadStatus.PENDING,
381
- // progress: 0,
382
- // error: undefined,
383
- // errorCode: undefined,
384
- // uploadId: '',
385
- // chunks: resetChunks,
386
- // retryCount: retryAttempt,
387
- // },
388
- // });
389
- // // Use startUpload for full retry
390
- // const resetFile: UploadFile = {
391
- // ...uploadFile,
392
- // status: UploadStatus.PENDING,
393
- // progress: 0,
394
- // error: undefined,
395
- // errorCode: undefined,
396
- // uploadId: '',
397
- // chunks: resetChunks,
398
- // retryCount: retryAttempt,
399
- // };
400
- // await startUpload(resetFile);
401
- // handlers.onRetry?.(uploadFile, 'full');
402
- // return { success: true, retryType: 'full' };
403
- // } catch (error) {
404
- // const uploadError = parseError(error, 'Retry failed');
405
- // console.error('Full retry failed:', uploadError.message);
406
- // dispatch({
407
- // type: 'UPDATE_FILE',
408
- // id: fileId,
409
- // updates: {
410
- // status: UploadStatus.FAILED,
411
- // error: uploadError.message,
412
- // errorCode: uploadError.code,
413
- // retryCount: retryAttempt,
414
- // },
415
- // });
416
- // handlers.onError?.(uploadFile, uploadError.originalError ?? new Error(uploadError.message));
417
- // return { success: false, retryType: 'full' };
418
- // }
419
- // }
420
- // },
421
- // [dispatch, getQueueManager, startUpload, ensureHandlers],
422
- // );
295
+ const retryUpload = useCallback((fileId_1, ...args_1) => __awaiter(this, [fileId_1, ...args_1], void 0, function* (fileId, forceFullRetry = false) {
296
+ var _a, _b;
297
+ const file = fileStateStore.getFile(fileId);
298
+ if (!file || !file.file) {
299
+ const error = createUploadError(UPLOAD_ERROR_CODE.MISSING_FILE, 'File is missing, cannot retry');
300
+ console.error(error.message);
301
+ return { success: false, retryType: 'smart' };
302
+ }
303
+ if (file.status !== UploadStatus.FAILED) {
304
+ return { success: false, retryType: 'smart' };
305
+ }
306
+ const h = ensureHandlers(file, dispatch);
307
+ if (!h) {
308
+ return { success: false, retryType: 'smart' };
309
+ }
310
+ const retryCount = ((_a = file.retryCount) !== null && _a !== void 0 ? _a : 0) + 1;
311
+ const failedChunksResult = getFailedChunks(file);
312
+ if (forceFullRetry || !failedChunksResult.hasFailed) {
313
+ return performFullRetry(file, h, retryCount);
314
+ }
315
+ // ─────────────────────────────────────────────────────────────────────────
316
+ // SMART RETRY: Retry only failed chunks
317
+ // ─────────────────────────────────────────────────────────────────────────
318
+ try {
319
+ const updatedChunks = resetFailedChunks(file.chunks);
320
+ const urlResult = yield h.onGetUploadUrls(file.fileName, file.chunks.length, file);
321
+ if (!urlResult.success) {
322
+ console.warn('Smart retry URL fetch failed, falling back to full retry');
323
+ return performFullRetry(file, h, retryCount);
324
+ }
325
+ const { uploadId, uploadUrls } = urlResult.uploadInfo;
326
+ const chunksWithUrls = applyUploadUrlsToChunks(updatedChunks, uploadUrls);
327
+ dispatch({
328
+ type: 'UPDATE_FILE',
329
+ id: fileId,
330
+ updates: {
331
+ status: UploadStatus.UPLOADING,
332
+ uploadId,
333
+ chunks: chunksWithUrls,
334
+ error: undefined,
335
+ errorCode: undefined,
336
+ retryCount,
337
+ },
338
+ });
339
+ handlerRegistry.register(fileId, h, 'retryUpload:smart');
340
+ const qm = getQueueManager();
341
+ qm.clearFileFromQueue(fileId);
342
+ const fileWithUrls = Object.assign(Object.assign({}, file), { uploadId, chunks: chunksWithUrls, status: UploadStatus.UPLOADING, retryCount, error: undefined, errorCode: undefined });
343
+ qm.addFile(fileWithUrls);
344
+ const ctx = getHandlerContext();
345
+ (_b = h.onRetry) === null || _b === void 0 ? void 0 : _b.call(h, file, 'smart', ctx);
346
+ return { success: true, retryType: 'smart' };
347
+ }
348
+ catch (error) {
349
+ const uploadError = parseError(error, 'Smart retry failed');
350
+ console.warn('Smart retry failed, falling back to full retry:', uploadError.message);
351
+ return performFullRetry(file, h, retryCount);
352
+ }
353
+ // ─────────────────────────────────────────────────────────────────────────
354
+ // FULL RETRY: Reset all chunks and start from beginning
355
+ // ─────────────────────────────────────────────────────────────────────────
356
+ function performFullRetry(uploadFile, handlers, retryAttempt) {
357
+ return __awaiter(this, void 0, void 0, function* () {
358
+ var _a, _b, _c;
359
+ try {
360
+ const resetChunks = resetAllChunks(uploadFile.chunks);
361
+ dispatch({
362
+ type: 'UPDATE_FILE',
363
+ id: fileId,
364
+ updates: {
365
+ status: UploadStatus.PENDING,
366
+ progress: 0,
367
+ error: undefined,
368
+ errorCode: undefined,
369
+ uploadId: '',
370
+ chunks: resetChunks,
371
+ retryCount: retryAttempt,
372
+ },
373
+ });
374
+ const resetFile = Object.assign(Object.assign({}, uploadFile), { status: UploadStatus.PENDING, progress: 0, error: undefined, errorCode: undefined, uploadId: '', chunks: resetChunks, retryCount: retryAttempt });
375
+ const ctx = getHandlerContext();
376
+ (_a = handlers.onRetry) === null || _a === void 0 ? void 0 : _a.call(handlers, uploadFile, 'full', ctx);
377
+ yield startUpload(resetFile);
378
+ return { success: true, retryType: 'full' };
379
+ }
380
+ catch (error) {
381
+ const uploadError = parseError(error, 'Retry failed');
382
+ console.error('Full retry failed:', uploadError.message);
383
+ dispatch({
384
+ type: 'UPDATE_FILE',
385
+ id: fileId,
386
+ updates: {
387
+ status: UploadStatus.FAILED,
388
+ error: uploadError.message,
389
+ errorCode: uploadError.code,
390
+ retryCount: retryAttempt,
391
+ },
392
+ });
393
+ const ctx = getHandlerContext();
394
+ (_b = handlers.onError) === null || _b === void 0 ? void 0 : _b.call(handlers, uploadFile, (_c = uploadError.originalError) !== null && _c !== void 0 ? _c : new Error(uploadError.message), ctx);
395
+ return { success: false, retryType: 'full' };
396
+ }
397
+ });
398
+ }
399
+ }), [dispatch, getQueueManager, startUpload]);
423
400
  // ─────────────────────────────────────────────────────────────────────────────
424
401
  // PUBLIC API
425
402
  // ─────────────────────────────────────────────────────────────────────────────
@@ -433,7 +410,7 @@ function useUploadEngine() {
433
410
  /** Cancel a file upload */
434
411
  cancelUpload,
435
412
  /** Retry a failed upload (smart retry with full retry fallback) */
436
- // retryUpload,
413
+ retryUpload,
437
414
  };
438
415
  }
439
416
 
@@ -60,7 +60,7 @@ import { useUploadEngine } from '../context/use-upload-engine.js';
60
60
  */
61
61
  function useUpload() {
62
62
  const { state, dispatch, config } = useUploadContext();
63
- const { startUpload, pauseUpload, resumeUpload, cancelUpload } = useUploadEngine();
63
+ const { startUpload, pauseUpload, resumeUpload, cancelUpload, retryUpload } = useUploadEngine();
64
64
  // ─────────────────────────────────────────────────────────────────────────────
65
65
  // FILE OPERATIONS
66
66
  // ─────────────────────────────────────────────────────────────────────────────
@@ -172,6 +172,18 @@ function useUpload() {
172
172
  * @param id - File ID to cancel
173
173
  */
174
174
  const cancel = useCallback((id) => cancelUpload(id), [cancelUpload]);
175
+ /**
176
+ * Retry a failed upload (smart retry with full retry fallback).
177
+ *
178
+ * @param id - File ID to retry
179
+ */
180
+ const retry = useCallback((id) => __awaiter(this, void 0, void 0, function* () {
181
+ const file = state.files.find((f) => f.id === id);
182
+ if (file && file.status === UploadStatus.FAILED) {
183
+ return retryUpload(id);
184
+ }
185
+ return { success: false, retryType: 'smart' };
186
+ }), [state.files, retryUpload]);
175
187
  // ─────────────────────────────────────────────────────────────────────────────
176
188
  // MUTEX FLAGS - Prevent concurrent batch operations
177
189
  // ─────────────────────────────────────────────────────────────────────────────
@@ -280,6 +292,7 @@ function useUpload() {
280
292
  pause,
281
293
  resume,
282
294
  cancel,
295
+ retry,
283
296
  getFileById,
284
297
  });
285
298
  });
@@ -297,6 +310,7 @@ function useUpload() {
297
310
  pause,
298
311
  resume,
299
312
  cancel,
313
+ retry,
300
314
  /** Get a specific file by ID */
301
315
  getFileById,
302
316
  /** Files waiting to be uploaded */
@@ -39,5 +39,47 @@ function resetInterruptedChunks(chunks) {
39
39
  return chunk;
40
40
  });
41
41
  }
42
+ /**
43
+ * Get chunks that failed and need to be retried.
44
+ * Returns only FAILED chunks, preserves COMPLETED chunks.
45
+ */
46
+ function getFailedChunks(file) {
47
+ const failedPartNums = [];
48
+ let completedCount = 0;
49
+ for (const chunk of file.chunks) {
50
+ if (chunk.status === ChunkStatus.COMPLETED) {
51
+ completedCount++;
52
+ }
53
+ else if (chunk.status === ChunkStatus.FAILED && chunk.partNum !== undefined) {
54
+ failedPartNums.push(chunk.partNum);
55
+ }
56
+ }
57
+ return {
58
+ failedPartNums,
59
+ failedCount: failedPartNums.length,
60
+ completedCount,
61
+ hasFailed: failedPartNums.length > 0,
62
+ };
63
+ }
64
+ /**
65
+ * Reset only failed chunks to pending state.
66
+ * Preserves completed chunks for efficient retry.
67
+ * Returns updated chunks array.
68
+ */
69
+ function resetFailedChunks(chunks) {
70
+ return chunks.map((chunk) => {
71
+ if (chunk.status === ChunkStatus.FAILED) {
72
+ return Object.assign(Object.assign({}, chunk), { status: ChunkStatus.PENDING, progress: 0, error: undefined });
73
+ }
74
+ return chunk;
75
+ });
76
+ }
77
+ /**
78
+ * Reset all chunks to pending state (for full retry).
79
+ * Used when smart retry fails or server state is lost.
80
+ */
81
+ function resetAllChunks(chunks) {
82
+ return chunks.map((chunk) => (Object.assign(Object.assign({}, chunk), { status: ChunkStatus.PENDING, progress: 0, error: undefined })));
83
+ }
42
84
 
43
- export { getChunksForResume, resetInterruptedChunks };
85
+ export { getChunksForResume, getFailedChunks, resetAllChunks, resetFailedChunks, resetInterruptedChunks };
@@ -0,0 +1,36 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { Modal, Space, Button } from 'antd';
3
+ import { isPublicNetwork } from '@zjlab-fe/util';
4
+ import { createRoot } from 'react-dom/client';
5
+
6
+ const LimitCreditModal = (props) => {
7
+ const isPublic = isPublicNetwork();
8
+ const handleOk = () => {
9
+ if (isPublic) {
10
+ window.open('https://alidocs.dingtalk.com/notable/share/form/v018oLl952Q1vXkzlap_dv19yqvsgs3oebp3pcjys_1qX0QQ0?source=link');
11
+ }
12
+ else {
13
+ window.open('https://alidocs.dingtalk.com/notable/share/form/v011X3lE5jKezRB4lJb_dv19yqvsgs3oebp3pcjys_1qX0QQ0?source=link');
14
+ }
15
+ };
16
+ return (jsx(Modal, Object.assign({}, props, {
17
+ // classNames={{
18
+ // content: 'modal-content-layout',
19
+ // header: 'modal-title-font modal-title-layout',
20
+ // body: 'modal-content-font modal-body-layout',
21
+ // footer: 'modal-footer-layout',
22
+ // }}
23
+ title: jsx("div", { style: { textAlign: 'center', width: '100%' }, children: "\u63D0\u793A" }), footer: jsx("div", { style: { display: 'flex', justifyContent: 'center' }, children: jsxs(Space, { children: [jsx(Button, { onClick: props.onCancel, children: "\u53D6\u6D88" }), jsx(Button, { type: "primary", onClick: handleOk, children: "\u7533\u8BF7" })] }) }), children: jsx("div", { className: "modal-content-font", style: { textAlign: 'center' }, children: "\u989D\u5EA6\u5DF2\u7528\u5C3D\uFF0C\u8BF7\u70B9\u51FB\u7533\u8BF7\u3002" }) })));
24
+ };
25
+ LimitCreditModal.open = () => {
26
+ const div = document.createElement('div');
27
+ document.body.appendChild(div);
28
+ const root = createRoot(div);
29
+ const destroy = () => {
30
+ root.unmount();
31
+ div.remove();
32
+ };
33
+ root.render(jsx(LimitCreditModal, { open: true, onCancel: destroy }));
34
+ };
35
+
36
+ export { LimitCreditModal as default };
@@ -0,0 +1,9 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import useStyle from './index.scss.js';
3
+
4
+ useStyle();
5
+ const TestComponent = (props) => {
6
+ return (jsxs("div", { className: "data-hub-ui-test-component-container", children: ["TestComponent Component", jsx("div", { children: "This is template, please delete it after you create your component." })] }));
7
+ };
8
+
9
+ export { TestComponent as default };
@@ -0,0 +1,7 @@
1
+ function useStyle() {
2
+ var style = document.createElement('style');
3
+ style.textContent = ``;
4
+ document.head.appendChild(style);
5
+ }
6
+
7
+ export { useStyle as default };
package/es/index.js CHANGED
@@ -9,6 +9,7 @@ export { Uploader as FileUploader } from './components/file-uploader/components/
9
9
  export { UploaderDropZone } from './components/file-uploader/components/uploader-drop-zone.js';
10
10
  export { UploaderFileListLayout } from './components/file-uploader/components/uploader-file-list.js';
11
11
  export { UploaderFileItem } from './components/file-uploader/components/uploader-file-item.js';
12
+ export { UploaderProgressBar } from './components/file-uploader/components/uploader-progress-bar.js';
12
13
  export { useUpload } from './components/file-uploader/hooks/use-upload.js';
13
14
  export { UploadStatus } from './components/file-uploader/constants.js';
14
15
  export { default as FilePreview } from './components/file-preview/index.js';
@@ -36,5 +37,6 @@ export { default as ModelCard } from './components/model-card/index.js';
36
37
  export { default as SDKModal } from './components/SDK-modal/index.js';
37
38
  export { default as TagView } from './components/tag-view/index.js';
38
39
  export { default as TagGroupFilter } from './components/tag-group-filter/index.js';
40
+ export { default as LimitCreditModal } from './components/limit-credit-modal/index.js';
39
41
  export { default as DatasetBatchAction, EDatasetBatchType } from './components/dataset-batch-action/index.js';
40
42
  export { default as UploadDrawerUploadStoreProvider } from './components/uploadDrawer/UploadStoreProvider.js';