@zjlab-fe/data-hub-ui 0.21.6 → 0.22.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 (226) hide show
  1. package/dist/types/components/tip-tap/extensions/index.d.ts +1 -1
  2. package/es/assets/cardImg.png.js +3 -0
  3. package/es/assets/closeBtn.png.js +3 -0
  4. package/es/assets/icon-tag-header.png.js +3 -0
  5. package/es/assets/source.png.js +3 -0
  6. package/es/components/FileUploader/FileUploadModal.js +24 -0
  7. package/es/components/FileUploader/FileUploader.js +20 -0
  8. package/es/components/FileUploader/FileUploaderImpl/FileUploader.js +34 -0
  9. package/es/components/FileUploader/FileUploaderImpl/FileUploaderContextProvider.js +46 -0
  10. package/es/components/FileUploader/FileUploaderImpl/FileUploaderFileReceiver.css.js +36 -0
  11. package/es/components/FileUploader/FileUploaderImpl/FileUploaderFileReceiver.js +57 -0
  12. package/es/components/FileUploader/FileUploaderImpl/FileUploaderFileReceiverContainer.js +24 -0
  13. package/es/components/FileUploader/FileUploaderImpl/FileUploaderFileReceiverDesc.js +9 -0
  14. package/es/components/FileUploader/FileUploaderImpl/FileUploaderList.js +46 -0
  15. package/es/components/FileUploader/FileUploaderImpl/FileUploaderListItem.js +46 -0
  16. package/es/components/FileUploader/FileUploaderImpl/FileUploaderListItemFail.js +21 -0
  17. package/es/components/FileUploader/FileUploaderImpl/FileUploaderListItemPaused.js +20 -0
  18. package/es/components/FileUploader/FileUploaderImpl/FileUploaderListItemUploading.js +43 -0
  19. package/es/components/FileUploader/FileUploaderImpl/FileUploaderlListItemFinished.js +32 -0
  20. package/es/components/FileUploader/Locale/translations.js +52 -0
  21. package/es/components/FileUploader/Locale/useTranslate.js +16 -0
  22. package/es/components/FileUploader/UploadStoreProvider/UploadStoreProvider.js +31 -0
  23. package/es/components/FileUploader/UploadStoreProvider/uploadStoreReducer.js +62 -0
  24. package/es/components/FileUploader/UploadStoreProvider/useOnFileAllUploaded.js +31 -0
  25. package/es/components/FileUploader/UploadStoreProvider/useSaveUnfinishedUploads.js +42 -0
  26. package/es/components/FileUploader/UploadStoreProvider/useSetupMergingEvent.js +45 -0
  27. package/es/components/FileUploader/hooks/useCancelUpload.js +40 -0
  28. package/es/components/FileUploader/hooks/useCurrentFile.js +61 -0
  29. package/es/components/FileUploader/hooks/useCurrentFileOnUploading.js +52 -0
  30. package/es/components/FileUploader/hooks/useCurrentFileSetupAndBackUp.js +39 -0
  31. package/es/components/FileUploader/hooks/useFormatFiles.js +64 -0
  32. package/es/components/FileUploader/hooks/useFormatFilesFindDuplicates.js +75 -0
  33. package/es/components/FileUploader/hooks/useFormatFilesRemoveDuplicates.js +21 -0
  34. package/es/components/FileUploader/hooks/useHandleChunkCompletion.js +31 -0
  35. package/es/components/FileUploader/hooks/useOnMounted.js +24 -0
  36. package/es/components/FileUploader/hooks/useOnMountedResumeUnfinished.js +58 -0
  37. package/es/components/FileUploader/hooks/useRetryUpload.js +33 -0
  38. package/es/components/FileUploader/hooks/useUploadChunk.js +46 -0
  39. package/es/components/FileUploader/icons/CloseFilled.js +7 -0
  40. package/es/components/FileUploader/icons/UnkownFileIcon.js +7 -0
  41. package/es/components/FileUploader/icons/UploadIcon.js +7 -0
  42. package/es/components/FileUploader/index.css.js +532 -0
  43. package/es/components/FileUploader/index.js +23 -0
  44. package/es/components/FileUploader/types.js +13 -0
  45. package/es/components/FileUploader/utils/calcDisplaySize.js +20 -0
  46. package/es/components/FileUploader/utils/checkExpiryTime.js +15 -0
  47. package/es/components/FileUploader/utils/createFileToUpload.js +60 -0
  48. package/es/components/FileUploader/utils/fileDB/addFilesToIndexdb.js +14 -0
  49. package/es/components/FileUploader/utils/fileDB/deleteFileInStore.js +18 -0
  50. package/es/components/FileUploader/utils/fileDB/deleteObjectStore.js +25 -0
  51. package/es/components/FileUploader/utils/fileDB/index.js +77 -0
  52. package/es/components/FileUploader/utils/fileDB/openDBAndRetrieveData.js +90 -0
  53. package/es/components/FileUploader/utils/fileDB/retrieveExistingData.js +49 -0
  54. package/es/components/FileUploader/utils/modalConfig.css.js +20 -0
  55. package/es/components/FileUploader/utils/modalConfig.js +32 -0
  56. package/es/components/FileUploader/utils/retrieveAllFiles.js +70 -0
  57. package/es/components/FileUploader/utils/splitFileIntoChunk.js +15 -0
  58. package/es/components/SDK-modal/document-link.js +8 -0
  59. package/es/components/SDK-modal/index.js +25 -0
  60. package/es/components/SDK-modal/index.module.scss.js +49 -0
  61. package/es/components/SDK-modal/inner-modal.js +59 -0
  62. package/es/components/SDK-modal/locale/translations.js +17 -0
  63. package/es/components/apply-perm-modal/index.js +53 -0
  64. package/es/components/apply-perm-modal/index.module.scss.js +96 -0
  65. package/es/components/auth-tag/index.js +23 -0
  66. package/es/components/bench-card/index.js +20 -0
  67. package/es/components/bench-card/index.module.scss.js +48 -0
  68. package/es/components/confirm-again/index.js +15 -0
  69. package/es/components/confirm-again/index.scss.js +37 -0
  70. package/es/components/copy/index.js +41 -0
  71. package/es/components/copy/index.module.scss.js +15 -0
  72. package/es/components/corpus-card/index.js +88 -0
  73. package/es/components/corpus-card/index.module.scss.js +171 -0
  74. package/es/components/feature-card/classNames.js +72 -0
  75. package/es/components/feature-card/components.js +48 -0
  76. package/es/components/feature-card/context.js +13 -0
  77. package/es/components/feature-card/index.css.js +655 -0
  78. package/es/components/feature-card/index.js +48 -0
  79. package/es/components/file-preview/data-table/index.js +94 -0
  80. package/es/components/file-preview/data-table/index.module.scss.js +54 -0
  81. package/es/components/file-preview/excel-preview/index.js +132 -0
  82. package/es/components/file-preview/excel-preview/index.module.scss.js +11 -0
  83. package/es/components/file-preview/excel-preview/utils.js +46 -0
  84. package/es/components/file-preview/img-preview/index.js +18 -0
  85. package/es/components/file-preview/img-preview/index.module.scss.js +17 -0
  86. package/es/components/file-preview/index.js +124 -0
  87. package/es/components/file-preview/index.module.scss.js +32 -0
  88. package/es/components/file-preview/json-preview/index.js +166 -0
  89. package/es/components/file-preview/markdown-preview/index.js +53 -0
  90. package/es/components/file-preview/markdown-preview/index.module.scss.js +1055 -0
  91. package/es/components/file-preview/parquet-preview/index.js +54 -0
  92. package/es/components/file-preview/pdf-preview/index.js +215 -0
  93. package/es/components/file-preview/pdf-preview/index.module.scss.js +16 -0
  94. package/es/components/file-preview/table-preview/index.js +43 -0
  95. package/es/components/file-preview/table-preview/index.module.scss.js +11 -0
  96. package/es/components/file-preview/txt-preview/index.js +24 -0
  97. package/es/components/file-preview/util.js +94 -0
  98. package/es/components/file-uploader/components/circle-progress.css.js +39 -0
  99. package/es/components/file-uploader/components/circle-progress.js +12 -0
  100. package/es/components/file-uploader/components/hooks/use-drop-zone.js +74 -0
  101. package/es/components/file-uploader/components/hooks/use-file-validation.js +52 -0
  102. package/es/components/file-uploader/components/icons.js +19 -0
  103. package/es/components/file-uploader/components/theme.css.js +64 -0
  104. package/es/components/file-uploader/components/uploader-drop-zone.css.js +66 -0
  105. package/es/components/file-uploader/components/uploader-drop-zone.js +74 -0
  106. package/es/components/file-uploader/components/uploader-file-item.css.js +186 -0
  107. package/es/components/file-uploader/components/uploader-file-item.js +63 -0
  108. package/es/components/file-uploader/components/uploader-file-list.css.js +43 -0
  109. package/es/components/file-uploader/components/uploader-file-list.js +27 -0
  110. package/es/components/file-uploader/components/uploader.css.js +20 -0
  111. package/es/components/file-uploader/components/uploader.js +51 -0
  112. package/es/components/file-uploader/components/uploading-status.css.js +52 -0
  113. package/es/components/file-uploader/components/uploading-status.js +54 -0
  114. package/es/components/file-uploader/components/utils/directory-reader.js +65 -0
  115. package/es/components/file-uploader/constants.js +31 -0
  116. package/es/components/file-uploader/context/action-registry.js +69 -0
  117. package/es/components/file-uploader/context/file-state-store.js +83 -0
  118. package/es/components/file-uploader/context/handler-registry.js +119 -0
  119. package/es/components/file-uploader/context/upload-context.js +36 -0
  120. package/es/components/file-uploader/context/upload-provider.js +77 -0
  121. package/es/components/file-uploader/context/upload-reducer.js +21 -0
  122. package/es/components/file-uploader/context/use-upload-engine.js +440 -0
  123. package/es/components/file-uploader/engine/queue-callbacks.js +257 -0
  124. package/es/components/file-uploader/engine/queue-manager.js +195 -0
  125. package/es/components/file-uploader/engine/queue-uploader.js +25 -0
  126. package/es/components/file-uploader/hooks/use-upload.js +327 -0
  127. package/es/components/file-uploader/utils/chunk-handlers.js +66 -0
  128. package/es/components/file-uploader/utils/ensure-handlers.js +53 -0
  129. package/es/components/file-uploader/utils/error-handler.js +84 -0
  130. package/es/components/file-uploader/utils/upload-controllers.js +43 -0
  131. package/es/components/file-uploader/utils/upload-handler.js +68 -0
  132. package/es/components/file-uploader/utils/validate-handlers.js +16 -0
  133. package/es/components/floating-label-input/index.js +46 -0
  134. package/es/components/floating-label-input/index.module.scss.js +30 -0
  135. package/es/components/floating-layer/index.js +15 -0
  136. package/es/components/floating-layer/index.scss.js +31 -0
  137. package/es/components/header/index.js +10 -0
  138. package/es/components/header/index.module.scss.js +16 -0
  139. package/es/components/input-tag/index.js +65 -0
  140. package/es/components/menu/index.js +96 -0
  141. package/es/components/menu/index.module.scss.js +188 -0
  142. package/es/components/model-card/index.js +20 -0
  143. package/es/components/model-card/index.module.scss.js +116 -0
  144. package/es/components/notion-editor/code-block/index.js +18 -0
  145. package/es/components/notion-editor/code-block/languageDetector.js +134 -0
  146. package/es/components/notion-editor/code-block/languages.js +42 -0
  147. package/es/components/notion-editor/index.js +258 -0
  148. package/es/components/notion-editor/index.scss.js +421 -0
  149. package/es/components/notion-editor/parseMarkdown.js +184 -0
  150. package/es/components/operator-chain/components/AddButton.js +20 -0
  151. package/es/components/operator-chain/components/IOCard.js +8 -0
  152. package/es/components/operator-chain/components/SingleCard.js +12 -0
  153. package/es/components/operator-chain/components/VirtualDropdown.js +56 -0
  154. package/es/components/operator-chain/index.js +83 -0
  155. package/es/components/operator-chain/index.module.scss.js +232 -0
  156. package/es/components/permission-editor/index.js +9 -0
  157. package/es/components/permission-editor/permissionEditModal/index.js +37 -0
  158. package/es/components/permission-editor/permissionEditor/index.js +253 -0
  159. package/es/components/permission-editor/permissionEditor/index.module.scss.js +22 -0
  160. package/es/components/permission-editor/permissionViewPopover/index.js +9 -0
  161. package/es/components/popover-select/index.js +42 -0
  162. package/es/components/popover-select/index.module.scss.js +22 -0
  163. package/es/components/radio-card/index.js +24 -0
  164. package/es/components/radio-card/index.scss.js +58 -0
  165. package/es/components/section-heading/classNames.js +22 -0
  166. package/es/components/section-heading/components.js +27 -0
  167. package/es/components/section-heading/context.js +13 -0
  168. package/es/components/section-heading/index.css.js +648 -0
  169. package/es/components/section-heading/index.js +37 -0
  170. package/es/components/status-tag/index.js +31 -0
  171. package/es/components/tag-group-filter/dataSizeFilter.js +100 -0
  172. package/es/components/tag-group-filter/index.js +53 -0
  173. package/es/components/tag-group-filter/index.module.scss.js +134 -0
  174. package/es/components/tag-group-filter/tagFilter.js +19 -0
  175. package/es/components/tag-view/index.js +138 -0
  176. package/es/components/tag-view/index.module.scss.js +56 -0
  177. package/es/components/tag-view/useSize.js +41 -0
  178. package/es/components/tip-tap/bubble-menu.js +47 -0
  179. package/es/components/tip-tap/editor.js +34 -0
  180. package/es/components/tip-tap/extensions/index.js +133 -0
  181. package/es/components/tip-tap/extensions/markdown-paste.js +148 -0
  182. package/es/components/tip-tap/icons/index.js +29 -0
  183. package/es/components/tip-tap/reader.js +15 -0
  184. package/es/components/tip-tap/styles/editor.css.js +863 -0
  185. package/es/components/tip-tap/toolbar/components/color-picker.js +76 -0
  186. package/es/components/tip-tap/toolbar/components/heading-dropdown.js +44 -0
  187. package/es/components/tip-tap/toolbar/components/image-button.js +26 -0
  188. package/es/components/tip-tap/toolbar/components/link-button.js +107 -0
  189. package/es/components/tip-tap/toolbar/components/table-button.js +37 -0
  190. package/es/components/tip-tap/toolbar/components/toolbar-button.js +7 -0
  191. package/es/components/tip-tap/toolbar/index.js +39 -0
  192. package/es/components/uploadDrawer/UploadStoreProvider.js +61 -0
  193. package/es/components/uploadDrawer/fileUploadDrawer.js +66 -0
  194. package/es/components/uploadDrawer/fileUploadDrawerFileDragger.js +71 -0
  195. package/es/components/uploadDrawer/fileUploadDrawerList.js +54 -0
  196. package/es/components/uploadDrawer/fileUploadDrawerListProgressButton.js +54 -0
  197. package/es/components/uploadDrawer/hooks/useCancelUpload.js +37 -0
  198. package/es/components/uploadDrawer/hooks/useFilterFiles.js +107 -0
  199. package/es/components/uploadDrawer/hooks/useFinishUpload.js +33 -0
  200. package/es/components/uploadDrawer/hooks/useFormatFiles.js +54 -0
  201. package/es/components/uploadDrawer/hooks/useProgressButtonRef.js +22 -0
  202. package/es/components/uploadDrawer/hooks/useRemoveFilesInUploadQueue.js +21 -0
  203. package/es/components/uploadDrawer/hooks/useResumeUnfinishedUploads.js +52 -0
  204. package/es/components/uploadDrawer/hooks/useRetryUpload.js +35 -0
  205. package/es/components/uploadDrawer/hooks/useSaveUnfinishedUploads.js +42 -0
  206. package/es/components/uploadDrawer/hooks/useSetupUpload.js +80 -0
  207. package/es/components/uploadDrawer/hooks/useUploadFileToOSS.js +23 -0
  208. package/es/components/uploadDrawer/index.css.js +511 -0
  209. package/es/components/uploadDrawer/index.js +43 -0
  210. package/es/components/uploadDrawer/utils/calcDisplaySize.js +19 -0
  211. package/es/components/uploadDrawer/utils/constant.js +16 -0
  212. package/es/components/uploadDrawer/utils/createFileToUpload.js +51 -0
  213. package/es/components/uploadDrawer/utils/fileDB/deleteFileInStore.js +28 -0
  214. package/es/components/uploadDrawer/utils/fileDB/deleteObjectStore.js +28 -0
  215. package/es/components/uploadDrawer/utils/fileDB/handleAddFilesToDB.js +37 -0
  216. package/es/components/uploadDrawer/utils/fileDB/index.js +9 -0
  217. package/es/components/uploadDrawer/utils/fileDB/openDB.js +111 -0
  218. package/es/components/uploadDrawer/utils/retrieveAllFiles.js +110 -0
  219. package/es/components/uploadDrawer/utils/shouldCreateNewFile.js +13 -0
  220. package/es/components/uploadDrawer/utils/splitFileIntoChunk.js +15 -0
  221. package/es/index.js +42 -1
  222. package/es/lib/utils.js +8 -0
  223. package/lib/index.js +1 -1
  224. package/package.json +164 -154
  225. package/rollup.es.config.mjs +177 -0
  226. package/tsconfig.rollup.json +7 -0
@@ -0,0 +1,54 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import './uploading-status.css.js';
4
+
5
+ const UPLOADING_MESSAGES = [
6
+ '上传中',
7
+ '传输数据中',
8
+ '正在处理',
9
+ '上传进行中',
10
+ '传输中,请稍候',
11
+ '文件上传中',
12
+ '数据传输中',
13
+ '上传处理中',
14
+ ];
15
+ function UploadingStatus({ interval = 10000, className = '' }) {
16
+ const [messageIndex, setMessageIndex] = useState(0);
17
+ const [animationState, setAnimationState] = useState('slide-in');
18
+ const [dots, setDots] = useState('.');
19
+ useEffect(() => {
20
+ const scheduleNextChange = () => {
21
+ // Random interval: ±30% of base interval (e.g., 3500-6500ms for 5000ms base)
22
+ const randomInterval = interval + (Math.random() - 0.5) * interval * 0.6;
23
+ const timer = setTimeout(() => {
24
+ // Start slide-up animation
25
+ setAnimationState('slide-up');
26
+ // Change message after slide-up completes
27
+ setTimeout(() => {
28
+ setMessageIndex((prev) => (prev + 1) % UPLOADING_MESSAGES.length);
29
+ setAnimationState('slide-in');
30
+ scheduleNextChange(); // Schedule next change
31
+ }, 400); // Match animation duration
32
+ }, randomInterval);
33
+ return timer;
34
+ };
35
+ const timer = scheduleNextChange();
36
+ return () => clearTimeout(timer);
37
+ }, [interval]);
38
+ // Animate dots: . -> .. -> ...
39
+ useEffect(() => {
40
+ const dotsTimer = setInterval(() => {
41
+ setDots((prev) => {
42
+ if (prev === '.')
43
+ return '..';
44
+ if (prev === '..')
45
+ return '...';
46
+ return '.';
47
+ });
48
+ }, 500); // Change dots every 500ms
49
+ return () => clearInterval(dotsTimer);
50
+ }, []);
51
+ return (jsxs("span", { className: `uploading-status ${className}`, children: [jsx("span", { className: `uploading-status-text ${animationState}`, children: UPLOADING_MESSAGES[messageIndex] }), jsx("span", { className: "uploading-dots", children: dots })] }));
52
+ }
53
+
54
+ export { UploadingStatus };
@@ -0,0 +1,65 @@
1
+ import { __awaiter } from 'tslib';
2
+
3
+ /**
4
+ * Recursively reads files from a FileSystemEntry (file or directory)
5
+ */
6
+ function readEntry(entry_1, acceptFilter_1) {
7
+ return __awaiter(this, arguments, void 0, function* (entry, acceptFilter, directory = true, basePath = '') {
8
+ const acceptSet = new Set(acceptFilter ? acceptFilter.split(',').map((s) => s.trim()) : []);
9
+ if (entry.isFile) {
10
+ return new Promise((resolve) => {
11
+ entry.file((file) => {
12
+ // Apply accept filter if specified
13
+ if (acceptSet.size > 0) {
14
+ const matchesFilter = Array.from(acceptSet).some((filter) => {
15
+ if (filter.startsWith('.')) {
16
+ return file.name.endsWith(filter);
17
+ }
18
+ if (filter.includes('/*')) {
19
+ const mimePrefix = filter.split('/')[0];
20
+ return file.type.startsWith(mimePrefix);
21
+ }
22
+ return file.type === filter;
23
+ });
24
+ if (!matchesFilter) {
25
+ resolve([]);
26
+ return;
27
+ }
28
+ }
29
+ const relativePath = basePath || '';
30
+ resolve([{ file, relativePath }]);
31
+ });
32
+ });
33
+ }
34
+ if (entry.isDirectory) {
35
+ // Skip directories if directory support is disabled
36
+ if (!directory) {
37
+ return [];
38
+ }
39
+ const dirReader = entry.createReader();
40
+ const entries = [];
41
+ const newBasePath = basePath ? `${basePath}/${entry.name}` : entry.name;
42
+ // Read all entries in directory
43
+ return new Promise((resolve) => {
44
+ const readEntries = () => {
45
+ dirReader.readEntries((results) => __awaiter(this, void 0, void 0, function* () {
46
+ if (results.length === 0) {
47
+ // Done reading directory
48
+ const filePromises = entries.map((e) => readEntry(e, acceptFilter, directory, newBasePath));
49
+ const fileArrays = yield Promise.all(filePromises);
50
+ resolve(fileArrays.flat());
51
+ }
52
+ else {
53
+ entries.push(...results);
54
+ readEntries(); // Continue reading
55
+ }
56
+ }));
57
+ };
58
+ readEntries();
59
+ });
60
+ }
61
+ return [];
62
+ });
63
+ }
64
+
65
+ export { readEntry };
@@ -0,0 +1,31 @@
1
+ // Size constants
2
+ const KB = 1024;
3
+ const MB = KB * 1024;
4
+ const GB = MB * 1024;
5
+ // Default configuration
6
+ const DEFAULT_CHUNK_SIZE = 10 * MB;
7
+ const DEFAULT_MAX_CHUNK_SIZE = 100 * MB;
8
+ const DEFAULT_MIN_CHUNK_SIZE = 5 * MB;
9
+ const DEFAULT_CONCURRENT_CHUNKS = 2;
10
+ const DEFAULT_CONCURRENT_FILES = 1;
11
+ const DEFAULT_MAX_FILE_SIZE = 10 * GB;
12
+ // Upload status enum
13
+ const UploadStatus = {
14
+ PENDING: 'pending',
15
+ PREPARING: 'preparing',
16
+ UPLOADING: 'uploading',
17
+ PAUSED: 'paused',
18
+ MERGING: 'merging',
19
+ SUCCESS: 'success',
20
+ FAILED: 'failed',
21
+ CANCELLED: 'cancelled',
22
+ };
23
+ // Chunk status enum
24
+ const ChunkStatus = {
25
+ PENDING: 'pending',
26
+ UPLOADING: 'uploading',
27
+ COMPLETED: 'completed',
28
+ FAILED: 'failed',
29
+ };
30
+
31
+ export { ChunkStatus, DEFAULT_CHUNK_SIZE, DEFAULT_CONCURRENT_CHUNKS, DEFAULT_CONCURRENT_FILES, DEFAULT_MAX_CHUNK_SIZE, DEFAULT_MAX_FILE_SIZE, DEFAULT_MIN_CHUNK_SIZE, GB, KB, MB, UploadStatus };
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Global action registry for providing fresh context to handlers.
3
+ *
4
+ * This registry stores references to the latest upload actions (removeFile, start, etc.)
5
+ * and state (files). It's updated on every render by useUpload hook, ensuring that
6
+ * when handlers are invoked, they receive always-current references.
7
+ *
8
+ * This solves the stale closure problem where handlers registered at file-add time
9
+ * would capture outdated versions of functions and state.
10
+ *
11
+ * Flow:
12
+ * 1. useUpload hook updates actionRegistry on every render with fresh refs
13
+ * 2. QueueManager callbacks (queue-callbacks.ts) invoke handlers
14
+ * 3. Before invoking, they call actionRegistry.getContext() to get fresh utilities
15
+ * 4. Handler receives fresh context, avoiding stale closure issues
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // In useUpload hook (automatic):
20
+ * useEffect(() => {
21
+ * actionRegistry.update({ files, removeFile, start, ... });
22
+ * });
23
+ *
24
+ * // In queue-callbacks.ts:
25
+ * const ctx = actionRegistry.getContext();
26
+ * handlers.onUploadSuccess?.(file, ctx);
27
+ * ```
28
+ */
29
+ class ActionRegistry {
30
+ constructor() {
31
+ this.context = null;
32
+ }
33
+ /**
34
+ * Update the stored context with fresh references.
35
+ * Called by useUpload hook on every render.
36
+ */
37
+ update(context) {
38
+ this.context = context;
39
+ }
40
+ /**
41
+ * Get the current context with fresh references.
42
+ * Returns null if context hasn't been initialized yet.
43
+ */
44
+ getContext() {
45
+ return this.context;
46
+ }
47
+ /**
48
+ * Check if context is available.
49
+ */
50
+ hasContext() {
51
+ return this.context !== null;
52
+ }
53
+ /**
54
+ * Clear the context.
55
+ * Mainly for testing or complete reset.
56
+ */
57
+ clear() {
58
+ this.context = null;
59
+ }
60
+ }
61
+ /**
62
+ * Singleton instance of the action registry.
63
+ * This is intentionally a module-level singleton, similar to handlerRegistry,
64
+ * because it needs to be accessible from queue-callbacks.ts which operates
65
+ * outside the React component tree.
66
+ */
67
+ const actionRegistry = new ActionRegistry();
68
+
69
+ export { actionRegistry };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Global file state store for background uploads.
3
+ *
4
+ * This store maintains a copy of file state that can be accessed
5
+ * even when the originating React component is unmounted.
6
+ *
7
+ * The store is updated whenever React state changes, ensuring
8
+ * QueueManager callbacks always have access to fresh file data.
9
+ *
10
+ * Flow:
11
+ * 1. UploadProvider updates state via reducer
12
+ * 2. Provider syncs state to this store via useEffect
13
+ * 3. QueueManager callbacks access files via getFile()
14
+ * 4. Even if user navigates away, store still has current data
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * // In UploadProvider - sync state to store
19
+ * useEffect(() => {
20
+ * fileStateStore.syncFiles(state.files);
21
+ * }, [state.files]);
22
+ *
23
+ * // In queue callbacks - get fresh file data
24
+ * const file = fileStateStore.getFile(fileId);
25
+ * ```
26
+ */
27
+ class FileStateStore {
28
+ constructor() {
29
+ /** Current files indexed by ID for O(1) lookup */
30
+ this.filesMap = new Map();
31
+ }
32
+ /**
33
+ * Sync files from React state to the global store.
34
+ * Called by UploadProvider whenever state.files changes.
35
+ */
36
+ syncFiles(files) {
37
+ // Clear and rebuild map for simplicity
38
+ // Could be optimized with incremental updates if needed
39
+ this.filesMap.clear();
40
+ for (const file of files) {
41
+ this.filesMap.set(file.id, file);
42
+ }
43
+ }
44
+ /**
45
+ * Get a file by ID.
46
+ * Returns undefined if file not found.
47
+ */
48
+ getFile(fileId) {
49
+ return this.filesMap.get(fileId);
50
+ }
51
+ /**
52
+ * Check if a file exists in the store.
53
+ */
54
+ hasFile(fileId) {
55
+ return this.filesMap.has(fileId);
56
+ }
57
+ /**
58
+ * Get all files (for debugging).
59
+ */
60
+ getAllFiles() {
61
+ return Array.from(this.filesMap.values());
62
+ }
63
+ /**
64
+ * Clear all files from the store.
65
+ * Called when UploadProvider unmounts.
66
+ */
67
+ clear() {
68
+ this.filesMap.clear();
69
+ }
70
+ /**
71
+ * Get the number of files in the store.
72
+ */
73
+ get size() {
74
+ return this.filesMap.size;
75
+ }
76
+ }
77
+ /**
78
+ * Singleton instance of the file state store.
79
+ * Shared across all upload components and QueueManager.
80
+ */
81
+ const fileStateStore = new FileStateStore();
82
+
83
+ export { fileStateStore };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Global handler registry for background uploads.
3
+ *
4
+ * This registry stores handlers per-file, allowing uploads to continue
5
+ * even when the user navigates away from the page that initiated the upload.
6
+ *
7
+ * Flow:
8
+ * 1. Component calls addFiles() -> handlers are registered per file ID
9
+ * 2. User navigates away -> component unmounts but handlers persist
10
+ * 3. QueueManager continues -> looks up handlers by file ID
11
+ * 4. Upload completes -> handlers are cleaned up
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * // In page component
16
+ * const { addFiles } = useUpload();
17
+ * addFiles(files, {
18
+ * getHandlers: (file) => ({
19
+ * onGetUploadUrls: (name, parts) => api.getUrls(datasetId, name, parts, folderFromUI()),
20
+ * // ... other handlers
21
+ * })
22
+ * });
23
+ *
24
+ * // When user adds files, handlers are registered:
25
+ * // handlerRegistry.register(file.id, handlers)
26
+ *
27
+ * // User navigates away - no problem!
28
+ * // QueueManager uses: handlerRegistry.get(fileId)
29
+ * ```
30
+ */
31
+ class HandlerRegistry {
32
+ constructor() {
33
+ this.registry = new Map();
34
+ }
35
+ /**
36
+ * Register handlers for a file.
37
+ * Called when a file is added for upload.
38
+ */
39
+ register(fileId, handlers, context) {
40
+ this.registry.set(fileId, {
41
+ handlers,
42
+ registeredAt: Date.now(),
43
+ context,
44
+ });
45
+ }
46
+ /**
47
+ * Get handlers for a file.
48
+ * Returns undefined if file has no registered handlers.
49
+ */
50
+ get(fileId) {
51
+ var _a;
52
+ return (_a = this.registry.get(fileId)) === null || _a === void 0 ? void 0 : _a.handlers;
53
+ }
54
+ /**
55
+ * Check if handlers exist for a file.
56
+ */
57
+ has(fileId) {
58
+ return this.registry.has(fileId);
59
+ }
60
+ /**
61
+ * Remove handlers for a file.
62
+ * Called when upload completes, fails permanently, or is cancelled.
63
+ */
64
+ unregister(fileId) {
65
+ this.registry.delete(fileId);
66
+ }
67
+ /**
68
+ * Get all registered file IDs.
69
+ * Useful for debugging and cleanup.
70
+ */
71
+ getRegisteredFileIds() {
72
+ return Array.from(this.registry.keys());
73
+ }
74
+ /**
75
+ * Get entry with metadata for debugging.
76
+ */
77
+ getEntry(fileId) {
78
+ return this.registry.get(fileId);
79
+ }
80
+ /**
81
+ * Clear all registrations.
82
+ * Use with caution - mainly for testing or complete reset.
83
+ */
84
+ clear() {
85
+ this.registry.clear();
86
+ }
87
+ /**
88
+ * Get count of registered handlers.
89
+ */
90
+ get size() {
91
+ return this.registry.size;
92
+ }
93
+ }
94
+ /**
95
+ * Singleton instance of the handler registry.
96
+ * This is intentionally a module-level singleton, not React context,
97
+ * because it needs to persist completely independently of React lifecycle.
98
+ */
99
+ const handlerRegistry = new HandlerRegistry();
100
+ /**
101
+ * Debug helper to log current registry state.
102
+ */
103
+ // export function debugHandlerRegistry(): void {
104
+ // console.group('🔧 Handler Registry Debug');
105
+ // console.log('Registered files:', handlerRegistry.getRegisteredFileIds());
106
+ // handlerRegistry.getRegisteredFileIds().forEach(id => {
107
+ // const entry = handlerRegistry.getEntry(id);
108
+ // console.log(` ${id}:`, {
109
+ // context: entry?.context,
110
+ // registeredAt: entry?.registeredAt ? new Date(entry.registeredAt).toISOString() : 'N/A',
111
+ // hasOnGetUploadUrls: !!entry?.handlers.onGetUploadUrls,
112
+ // hasOnPartComplete: !!entry?.handlers.onPartComplete,
113
+ // hasOnFileComplete: !!entry?.handlers.onFileComplete,
114
+ // });
115
+ // });
116
+ // console.groupEnd();
117
+ // }
118
+
119
+ export { handlerRegistry };
@@ -0,0 +1,36 @@
1
+ import { createContext, useContext } from 'react';
2
+ import { DEFAULT_CONCURRENT_FILES, DEFAULT_CONCURRENT_CHUNKS, DEFAULT_MIN_CHUNK_SIZE, DEFAULT_MAX_CHUNK_SIZE } from '../constants.js';
3
+
4
+ // Initial empty upload state
5
+ const initialUploadState = {
6
+ files: [],
7
+ };
8
+ /**
9
+ * Default upload configuration (Provider level).
10
+ * Controls chunk sizes and concurrency - typically same across app.
11
+ */
12
+ const defaultUploadConfig = {
13
+ maxChunkSize: DEFAULT_MAX_CHUNK_SIZE,
14
+ minChunkSize: DEFAULT_MIN_CHUNK_SIZE,
15
+ concurrentChunks: DEFAULT_CONCURRENT_CHUNKS,
16
+ concurrentFiles: DEFAULT_CONCURRENT_FILES,
17
+ };
18
+ // Upload context - null before provider mounts
19
+ const UploadContext = createContext(null);
20
+ // Display name for React DevTools
21
+ UploadContext.displayName = 'UploadContext';
22
+ /**
23
+ * Hook to consume upload context
24
+ * Must be used within UploadProvider
25
+ * @throws Error if used outside of UploadProvider
26
+ */
27
+ function useUploadContext() {
28
+ const context = useContext(UploadContext);
29
+ if (!context) {
30
+ throw new Error('useUploadContext must be used within UploadProvider. ' +
31
+ 'Make sure your component is wrapped with <UploadProvider>.');
32
+ }
33
+ return context;
34
+ }
35
+
36
+ export { UploadContext, defaultUploadConfig, initialUploadState, useUploadContext };
@@ -0,0 +1,77 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useReducer, useMemo, useRef, useEffect, useCallback } from 'react';
3
+ import { initialUploadState, defaultUploadConfig, UploadContext } from './upload-context.js';
4
+ import { uploadReducer } from './upload-reducer.js';
5
+ import { fileStateStore } from './file-state-store.js';
6
+ import { QueueManager } from '../engine/queue-manager.js';
7
+ import { createQueueCallbacks } from '../engine/queue-callbacks.js';
8
+
9
+ /**
10
+ * Upload Provider Component
11
+ *
12
+ * Provides shared upload state and global configuration across the application.
13
+ * Manages:
14
+ * - Files state (list of files, their status, progress)
15
+ * - QueueManager singleton (shared upload queue)
16
+ * - Global config (chunk sizes, concurrency)
17
+ *
18
+ * For persistence support, wrap your app with PersistenceProvider inside UploadProvider:
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * // App level - state management + global config
23
+ * <UploadProvider config={{ concurrentFiles: 3 }}>
24
+ * <PersistenceProvider config={{ mode: 'indexeddb' }}>
25
+ * <App />
26
+ * </PersistenceProvider>
27
+ * </UploadProvider>
28
+ *
29
+ * // In App - use persistence hook
30
+ * const { pendingFiles, restoreFiles } = usePersistence();
31
+ *
32
+ * // Component level - provide handlers & per-usage options
33
+ * const { addFiles } = useUpload();
34
+ * ```
35
+ */
36
+ function UploadProvider({ config, children }) {
37
+ // State management with reducer
38
+ const [state, dispatch] = useReducer(uploadReducer, initialUploadState);
39
+ // Merge user config with defaults
40
+ const mergedConfig = useMemo(() => (Object.assign(Object.assign({}, defaultUploadConfig), config)), [config]);
41
+ // Shared QueueManager ref - singleton across all useUploadEngine consumers
42
+ const queueManagerRef = useRef(null);
43
+ // Sync file state to global store for background upload support
44
+ // This ensures QueueManager callbacks always have fresh file data
45
+ useEffect(() => {
46
+ fileStateStore.syncFiles(state.files);
47
+ }, [state.files]);
48
+ /**
49
+ * Get or create QueueManager instance with lazy initialization.
50
+ * This is stable across renders and shared by all consumers.
51
+ */
52
+ const getQueueManager = useCallback(() => {
53
+ if (queueManagerRef.current) {
54
+ return queueManagerRef.current;
55
+ }
56
+ const queueConfig = {
57
+ concurrentFiles: mergedConfig.concurrentFiles,
58
+ concurrentChunks: mergedConfig.concurrentChunks,
59
+ };
60
+ const callbacks = createQueueCallbacks({ dispatch });
61
+ queueManagerRef.current = new QueueManager(queueConfig, callbacks);
62
+ return queueManagerRef.current;
63
+ }, [mergedConfig.concurrentFiles, mergedConfig.concurrentChunks, dispatch]);
64
+ // Memoize context value to prevent unnecessary re-renders
65
+ const contextValue = useMemo(() => ({
66
+ state,
67
+ dispatch,
68
+ config: mergedConfig,
69
+ queueManagerRef,
70
+ getQueueManager,
71
+ }), [state, mergedConfig, getQueueManager]);
72
+ return jsx(UploadContext.Provider, { value: contextValue, children: children });
73
+ }
74
+ // Display name for React DevTools
75
+ UploadProvider.displayName = 'UploadProvider';
76
+
77
+ export { UploadProvider };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Reducer for upload state management
3
+ * Handles all file upload state transitions
4
+ */
5
+ function uploadReducer(state, action) {
6
+ switch (action.type) {
7
+ case 'ADD_FILES':
8
+ return Object.assign(Object.assign({}, state), { files: [...state.files, ...action.files] });
9
+ case 'UPDATE_FILE':
10
+ return Object.assign(Object.assign({}, state), { files: state.files.map((file) => (file.id === action.id ? Object.assign(Object.assign({}, file), action.updates) : file)) });
11
+ case 'UPDATE_CHUNK':
12
+ return Object.assign(Object.assign({}, state), { files: state.files.map((file) => file.id === action.fileId
13
+ ? Object.assign(Object.assign({}, file), { chunks: file.chunks.map((chunk) => chunk.partNum === action.partNum ? Object.assign(Object.assign({}, chunk), action.updates) : chunk) }) : file) });
14
+ case 'REMOVE_FILE':
15
+ return Object.assign(Object.assign({}, state), { files: state.files.filter((file) => file.id !== action.id) });
16
+ default:
17
+ return state;
18
+ }
19
+ }
20
+
21
+ export { uploadReducer };