| | |
| | | import I18n from '@/context/i18n' |
| | | import { LanguagesSupported } from '@/i18n/language' |
| | | import { IS_CE_EDITION } from '@/config' |
| | | import { useAppContext } from '@/context/app-context' |
| | | import { Theme } from '@/types/app' |
| | | import useTheme from '@/hooks/use-theme' |
| | | |
| | | const FILES_NUMBER_LIMIT = 20 |
| | | |
| | |
| | | e.stopPropagation() |
| | | e.target === dragRef.current && setDragging(false) |
| | | } |
| | | type FileWithPath = { |
| | | relativePath?: string |
| | | } & File |
| | | const traverseFileEntry = useCallback( |
| | | (entry: any, prefix = ''): Promise<FileWithPath[]> => { |
| | | return new Promise((resolve) => { |
| | | if (entry.isFile) { |
| | | entry.file((file: FileWithPath) => { |
| | | file.relativePath = `${prefix}${file.name}` |
| | | resolve([file]) |
| | | }) |
| | | } |
| | | else if (entry.isDirectory) { |
| | | const reader = entry.createReader() |
| | | const entries: any[] = [] |
| | | const read = () => { |
| | | reader.readEntries(async (results: FileSystemEntry[]) => { |
| | | if (!results.length) { |
| | | const files = await Promise.all( |
| | | entries.map(ent => |
| | | traverseFileEntry(ent, `${prefix}${entry.name}/`), |
| | | ), |
| | | ) |
| | | resolve(files.flat()) |
| | | } |
| | | else { |
| | | entries.push(...results) |
| | | read() |
| | | } |
| | | }) |
| | | } |
| | | read() |
| | | } |
| | | else { |
| | | resolve([]) |
| | | } |
| | | }) |
| | | }, |
| | | [], |
| | | ) |
| | | |
| | | const handleDrop = useCallback( |
| | | async (e: DragEvent) => { |
| | | e.preventDefault() |
| | | e.stopPropagation() |
| | | setDragging(false) |
| | | if (!e.dataTransfer) return |
| | | const nested = await Promise.all( |
| | | Array.from(e.dataTransfer.items).map((it) => { |
| | | const entry = (it as any).webkitGetAsEntry?.() |
| | | if (entry) return traverseFileEntry(entry) |
| | | const f = it.getAsFile?.() |
| | | return f ? Promise.resolve([f]) : Promise.resolve([]) |
| | | }), |
| | | ) |
| | | let files = nested.flat() |
| | | if (notSupportBatchUpload) files = files.slice(0, 1) |
| | | const valid = files.filter(isValid) |
| | | initialUpload(valid) |
| | | }, |
| | | [initialUpload, isValid, notSupportBatchUpload, traverseFileEntry], |
| | | ) |
| | | const handleDrop = useCallback((e: DragEvent) => { |
| | | e.preventDefault() |
| | | e.stopPropagation() |
| | | setDragging(false) |
| | | if (!e.dataTransfer) |
| | | return |
| | | |
| | | const files = [...e.dataTransfer.files] as File[] |
| | | const validFiles = files.filter(isValid) |
| | | initialUpload(validFiles) |
| | | }, [initialUpload, isValid]) |
| | | |
| | | const selectHandle = () => { |
| | | if (fileUploader.current) |
| | | fileUploader.current.click() |
| | |
| | | initialUpload(files.filter(isValid)) |
| | | }, [isValid, initialUpload]) |
| | | |
| | | const { theme } = useTheme() |
| | | const { theme } = useAppContext() |
| | | const chartColor = useMemo(() => theme === Theme.dark ? '#5289ff' : '#296dff', [theme]) |
| | | |
| | | useEffect(() => { |
| | |
| | | /> |
| | | )} |
| | | |
| | | <div className={cn('mb-1 text-sm font-semibold leading-6 text-text-secondary', titleClassName)}>{t('datasetCreation.stepOne.uploader.title')}</div> |
| | | <div className={cn('text-text-tertiary text-sm font-semibold leading-6 mb-1', titleClassName)}>{t('datasetCreation.stepOne.uploader.title')}</div> |
| | | |
| | | {!hideUpload && ( |
| | | <div ref={dropRef} className={cn('relative mb-2 box-border flex min-h-20 max-w-[640px] flex-col items-center justify-center gap-1 rounded-xl border border-dashed border-components-dropzone-border bg-components-dropzone-bg px-4 py-3 text-xs leading-4 text-text-tertiary', dragging && 'border-components-dropzone-border-accent bg-components-dropzone-bg-accent')}> |
| | | <div className="flex min-h-5 items-center justify-center text-sm leading-4 text-text-secondary"> |
| | | <div ref={dropRef} className={cn('relative box-border flex flex-col justify-center items-center gap-1 mb-2 px-4 py-3 max-w-[640px] min-h-20 leading-4 text-xs text-text-tertiary bg-components-dropzone-bg border border-dashed border-components-dropzone-border rounded-xl', dragging && 'bg-components-dropzone-bg-accent border-components-dropzone-border-accent')}> |
| | | <div className="flex justify-center items-center min-h-5 text-sm leading-4 text-text-secondary"> |
| | | <RiUploadCloud2Line className='mr-2 size-5' /> |
| | | |
| | | <span> |
| | | {t('datasetCreation.stepOne.uploader.button')} |
| | | {supportTypes.length > 0 && ( |
| | | <label className="ml-1 cursor-pointer text-text-accent" onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.browse')}</label> |
| | | <label className="ml-1 text-text-accent cursor-pointer" onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.browse')}</label> |
| | | )} |
| | | </span> |
| | | </div> |
| | |
| | | size: fileUploadConfig.file_size_limit, |
| | | supportTypes: supportTypesShowNames, |
| | | })}</div> |
| | | {dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />} |
| | | {dragging && <div ref={dragRef} className='absolute top-0 left-0 w-full h-full' />} |
| | | </div> |
| | | )} |
| | | <div className='max-w-[640px] cursor-default space-y-1'> |
| | | <div className='space-y-1 max-w-[640px] cursor-default'> |
| | | |
| | | {fileList.map((fileItem, index) => ( |
| | | <div |
| | | key={`${fileItem.fileID}-${index}`} |
| | | onClick={() => fileItem.file?.id && onPreview(fileItem.file)} |
| | | className={cn( |
| | | 'flex h-12 max-w-[640px] items-center rounded-lg border border-components-panel-border bg-components-panel-on-panel-item-bg text-xs leading-3 text-text-tertiary shadow-xs', |
| | | 'flex items-center h-12 max-w-[640px] bg-components-panel-on-panel-item-bg text-xs leading-3 text-text-tertiary border border-components-panel-border rounded-lg shadow-xs', |
| | | // 'border-state-destructive-border bg-state-destructive-hover', |
| | | )} |
| | | > |
| | | <div className="flex w-12 shrink-0 items-center justify-center"> |
| | | <div className="shrink-0 flex justify-center items-center w-12"> |
| | | <DocumentFileIcon |
| | | className="size-6 shrink-0" |
| | | className="shrink-0 size-6" |
| | | name={fileItem.file.name} |
| | | extension={getFileType(fileItem.file)} |
| | | /> |
| | | </div> |
| | | <div className="flex shrink grow flex-col gap-0.5"> |
| | | <div className="grow shrink flex flex-col gap-0.5"> |
| | | <div className='flex w-full'> |
| | | <div className="w-0 grow truncate text-sm leading-4 text-text-secondary">{fileItem.file.name}</div> |
| | | <div className="text-sm leading-4 text-text-secondary w-0 grow truncate">{fileItem.file.name}</div> |
| | | </div> |
| | | <div className="w-full truncate leading-3 text-text-tertiary"> |
| | | <div className="w-full leading-3 truncate text-text-tertiary"> |
| | | <span className='uppercase'>{getFileType(fileItem.file)}</span> |
| | | <span className='px-1 text-text-quaternary'>·</span> |
| | | <span>{getFileSize(fileItem.file.size)}</span> |
| | |
| | | <span>10k characters</span> */} |
| | | </div> |
| | | </div> |
| | | <div className="flex w-16 shrink-0 items-center justify-end gap-1 pr-3"> |
| | | <div className="shrink-0 flex items-center justify-end gap-1 pr-3 w-16"> |
| | | {/* <span className="flex justify-center items-center w-6 h-6 cursor-pointer"> |
| | | <RiErrorWarningFill className='size-4 text-text-warning' /> |
| | | </span> */} |
| | |
| | | // <div className={s.percent}>{`${fileItem.progress}%`}</div> |
| | | <SimplePieChart percentage={fileItem.progress} stroke={chartColor} fill={chartColor} animationDuration={0} /> |
| | | )} |
| | | <span className="flex h-6 w-6 cursor-pointer items-center justify-center" onClick={(e) => { |
| | | <span className="flex justify-center items-center w-6 h-6 cursor-pointer" onClick={(e) => { |
| | | e.stopPropagation() |
| | | removeFile(fileItem.fileID) |
| | | }}> |