import { DeleteOutlined, EditOutlined, ExclamationCircleOutlined, FileImageOutlined, FilePdfOutlined, FileTextOutlined, SortAscendingOutlined, SortDescendingOutlined } from '@ant-design/icons' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import TextEditPopup from '@renderer/components/Popups/TextEditPopup' import db from '@renderer/databases' import { useProviders } from '@renderer/hooks/useProvider' import FileManager from '@renderer/services/FileManager' import store from '@renderer/store' import { FileType, FileTypes } from '@renderer/types' import { formatFileSize } from '@renderer/utils' import type { MenuProps } from 'antd' import { Button, Empty, Flex, Menu, Popconfirm } from 'antd' import dayjs from 'dayjs' import { useLiveQuery } from 'dexie-react-hooks' import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' import FileList from './FileList' type SortField = 'created_at' | 'size' | 'name' type SortOrder = 'asc' | 'desc' const FilesPage: FC = () => { const { t } = useTranslation() const [fileType, setFileType] = useState('document') const [sortField, setSortField] = useState('created_at') const [sortOrder, setSortOrder] = useState('desc') const { providers } = useProviders() const geminiProviders = providers.filter((provider) => provider.type === 'gemini') const tempFilesSort = (files: FileType[]) => { return files.sort((a, b) => { const aIsTemp = a.origin_name.startsWith('temp_file') const bIsTemp = b.origin_name.startsWith('temp_file') if (aIsTemp && !bIsTemp) return 1 if (!aIsTemp && bIsTemp) return -1 return 0 }) } const sortFiles = (files: FileType[]) => { return [...files].sort((a, b) => { let comparison = 0 switch (sortField) { case 'created_at': comparison = dayjs(a.created_at).unix() - dayjs(b.created_at).unix() break case 'size': comparison = a.size - b.size break case 'name': comparison = a.origin_name.localeCompare(b.origin_name) break } return sortOrder === 'asc' ? comparison : -comparison }) } const files = useLiveQuery(() => { if (fileType === 'all') { return db.files.orderBy('count').toArray().then(tempFilesSort) } return db.files.where('type').equals(fileType).sortBy('count').then(tempFilesSort) }, [fileType]) const sortedFiles = files ? sortFiles(files) : [] const handleDelete = async (fileId: string) => { const file = await FileManager.getFile(fileId) const paintings = await store.getState().paintings.paintings const paintingsFiles = paintings.flatMap((p) => p.files) if (paintingsFiles.some((p) => p.id === fileId)) { window.modal.warning({ content: t('files.delete.paintings.warning'), centered: true }) return } if (file) { await FileManager.deleteFile(fileId, true) } const topics = await db.topics .filter((topic) => topic.messages.some((message) => message.files?.some((f) => f.id === fileId))) .toArray() if (topics.length > 0) { for (const topic of topics) { const updatedMessages = topic.messages.map((message) => ({ ...message, files: message.files?.filter((f) => f.id !== fileId) })) await db.topics.update(topic.id, { messages: updatedMessages }) } } } const handleRename = async (fileId: string) => { const file = await FileManager.getFile(fileId) if (file) { const newName = await TextEditPopup.show({ text: file.origin_name }) if (newName) { FileManager.updateFile({ ...file, origin_name: newName }) } } } const dataSource = sortedFiles?.map((file) => { return { key: file.id, file: window.api.file.openPath(file.path)}>{FileManager.formatFileName(file)}, size: formatFileSize(file.size), size_bytes: file.size, count: file.count, path: file.path, ext: file.ext, created_at: dayjs(file.created_at).format('MM-DD HH:mm'), created_at_unix: dayjs(file.created_at).unix(), actions: (