diff --git a/api/src/Erp.Platform.Application.Contracts/FileManagement/FileItemDto.cs b/api/src/Erp.Platform.Application.Contracts/FileManagement/FileItemDto.cs index 841bb9a0..9996a2df 100644 --- a/api/src/Erp.Platform.Application.Contracts/FileManagement/FileItemDto.cs +++ b/api/src/Erp.Platform.Application.Contracts/FileManagement/FileItemDto.cs @@ -17,6 +17,7 @@ public class FileItemDto public string ParentId { get; set; } = string.Empty; public bool IsReadOnly { get; set; } public int? ChildCount { get; set; } + public string TenantId { get; set; } = string.Empty; } public class GetFilesDto diff --git a/api/src/Erp.Platform.Application/FileManagement/FileManagementAppService.cs b/api/src/Erp.Platform.Application/FileManagement/FileManagementAppService.cs index fe370164..15d60f35 100644 --- a/api/src/Erp.Platform.Application/FileManagement/FileManagementAppService.cs +++ b/api/src/Erp.Platform.Application/FileManagement/FileManagementAppService.cs @@ -50,7 +50,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe private string GetTenantPrefix() { var tenantId = _currentTenant.Id?.ToString() ?? "host"; - return $"files/{tenantId}/"; + return $"tenants/{tenantId}/"; } private string EncodePathAsId(string path) @@ -241,7 +241,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe Path = metadata.Path, ParentId = parentId ?? string.Empty, IsReadOnly = finalIsReadOnly, - ChildCount = metadata.ChildCount + ChildCount = metadata.ChildCount, + TenantId = metadata.TenantId }; }).OrderBy(x => x.Type == "folder" ? 0 : 1).ThenBy(x => x.Name).ToList(); @@ -309,7 +310,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = metadata.ModifiedAt, Path = metadata.Path, ParentId = input.ParentId ?? string.Empty, - IsReadOnly = metadata.IsReadOnly + IsReadOnly = metadata.IsReadOnly, + TenantId = _currentTenant.Id?.ToString() }; } @@ -401,7 +403,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = metadata.ModifiedAt, Path = metadata.Path, ParentId = input.ParentId ?? string.Empty, - IsReadOnly = metadata.IsReadOnly + IsReadOnly = metadata.IsReadOnly, + TenantId = _currentTenant.Id?.ToString() }; } @@ -468,7 +471,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = metadata.ModifiedAt, Path = metadata.Path, ParentId = metadata.ParentId, - IsReadOnly = metadata.IsReadOnly + IsReadOnly = metadata.IsReadOnly, + TenantId = _currentTenant.Id?.ToString() }; } @@ -530,7 +534,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = metadata.ModifiedAt, Path = metadata.Path, ParentId = metadata.ParentId, - IsReadOnly = metadata.IsReadOnly + IsReadOnly = metadata.IsReadOnly, + TenantId = _currentTenant.Id?.ToString() }; } @@ -675,7 +680,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = dirInfo.LastWriteTime, Path = finalTargetPath, ParentId = input.TargetFolderId ?? string.Empty, - IsReadOnly = false + IsReadOnly = false, + TenantId = _currentTenant.Id?.ToString() }); } else if (File.Exists(sourceFullPath)) @@ -704,7 +710,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = fileInfo.LastWriteTime, Path = finalTargetPath, ParentId = input.TargetFolderId ?? string.Empty, - IsReadOnly = false + IsReadOnly = false, + TenantId = _currentTenant.Id?.ToString() }); } else @@ -800,7 +807,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = dirInfo.LastWriteTime, Path = finalTargetPath, ParentId = input.TargetFolderId ?? string.Empty, - IsReadOnly = false + IsReadOnly = false, + TenantId = _currentTenant.Id?.ToString() }); } else if (File.Exists(sourceFullPath)) @@ -829,7 +837,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = fileInfo.LastWriteTime, Path = finalTargetPath, ParentId = input.TargetFolderId ?? string.Empty, - IsReadOnly = false + IsReadOnly = false, + TenantId = _currentTenant.Id?.ToString() }); } else @@ -895,7 +904,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe ModifiedAt = metadata.ModifiedAt, Path = metadata.Path, ParentId = metadata.ParentId, - IsReadOnly = metadata.IsReadOnly + IsReadOnly = metadata.IsReadOnly, + TenantId = _currentTenant.Id?.ToString() }) .OrderBy(x => x.Type == "folder" ? 0 : 1) .ThenBy(x => x.Name) diff --git a/api/src/Erp.Platform.Application/Intranet/IntranetAppService.cs b/api/src/Erp.Platform.Application/Intranet/IntranetAppService.cs index bb44be79..da9cbbc4 100644 --- a/api/src/Erp.Platform.Application/Intranet/IntranetAppService.cs +++ b/api/src/Erp.Platform.Application/Intranet/IntranetAppService.cs @@ -462,7 +462,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService Path = relativePath, ParentId = string.Empty, IsReadOnly = false, - ChildCount = 0 + ChildCount = 0, + TenantId = _currentTenant.Id?.ToString() }); } diff --git a/ui/src/constants/app.constant.ts b/ui/src/constants/app.constant.ts index d19bf571..5c7075ad 100644 --- a/ui/src/constants/app.constant.ts +++ b/ui/src/constants/app.constant.ts @@ -6,7 +6,9 @@ export const REDIRECT_URL_KEY = 'redirectUrl' export const DEFAULT_API_NAME = 'Default' export const AUTH_API_NAME = 'AuthApi' export const AVATAR_URL = (id?: string, tenantId?: string) => - `${VITE_CDN_URL}/${tenantId ? 'tenants/' + tenantId : 'host'}/Avatar/${id ?? 'default'}.jpg` + `${VITE_CDN_URL}/${tenantId ? 'tenants/' + tenantId : 'host'}/avatar/${id ?? 'default'}.jpg` export const MULTIVALUE_DELIMITER = '|' export const DX_CLASSNAMES = 'dx-viewport dx-device-desktop dx-device-generic dx-theme-generic dx-theme-generic-typography dx-color-scheme-light' +export const FILE_URL = (fileName?: string, tenantId?: string) => + `${VITE_CDN_URL}/${tenantId ? 'tenants/' + tenantId : 'host'}/${fileName}` \ No newline at end of file diff --git a/ui/src/types/fileManagement.ts b/ui/src/types/fileManagement.ts index 23e85493..cfa9f000 100644 --- a/ui/src/types/fileManagement.ts +++ b/ui/src/types/fileManagement.ts @@ -11,6 +11,7 @@ export interface FileItem { extension: string isReadOnly: boolean childCount?: number // Klasörler için öğe sayısı + tenantId?: string } export interface FolderItem extends Omit { diff --git a/ui/src/views/admin/files/FileManager.tsx b/ui/src/views/admin/files/FileManager.tsx index acac58df..975adc50 100644 --- a/ui/src/views/admin/files/FileManager.tsx +++ b/ui/src/views/admin/files/FileManager.tsx @@ -85,20 +85,20 @@ const FileManager = () => { } }) - console.log('Fetched items:', protectedItems) - console.log( - 'Protected folders check:', - protectedItems.filter((item) => item.isReadOnly), - ) - console.log( - 'Folders with childCount:', - protectedItems.filter((item) => item.type === 'folder').map(item => ({ - name: item.name, - childCount: item.childCount, - hasChildCount: 'childCount' in item, - type: typeof item.childCount - })) - ) + // console.log('Fetched items:', protectedItems) + // console.log( + // 'Protected folders check:', + // protectedItems.filter((item) => item.isReadOnly), + // ) + // console.log( + // 'Folders with childCount:', + // protectedItems.filter((item) => item.type === 'folder').map(item => ({ + // name: item.name, + // childCount: item.childCount, + // hasChildCount: 'childCount' in item, + // type: typeof item.childCount + // })) + // ) setItems(protectedItems) } catch (error) { console.error('Failed to fetch items:', error) @@ -117,7 +117,7 @@ const FileManager = () => { } const response = await fileManagementService.getFolderPath(folderId) - console.log('Breadcrumb response for folderId:', folderId, response) + // console.log('Breadcrumb response for folderId:', folderId, response) const pathItems: BreadcrumbItem[] = [ { name: 'Files', path: '', id: undefined }, ...response.data.path.map((item) => ({ @@ -236,13 +236,6 @@ const FileManager = () => { formData.append('parentId', currentFolderId) } - console.log('FileManager uploading:', { - fileName: file.name, - fileSize: file.size, - fileType: file.type, - parentId: currentFolderId, - }) - await fileManagementService.uploadFileDirectly(formData) } await fetchItems(currentFolderId) diff --git a/ui/src/views/admin/files/components/FileItem.tsx b/ui/src/views/admin/files/components/FileItem.tsx index e7cccb3c..7ae2a47f 100644 --- a/ui/src/views/admin/files/components/FileItem.tsx +++ b/ui/src/views/admin/files/components/FileItem.tsx @@ -8,15 +8,17 @@ import { FaFilm, FaMusic, FaArchive, - FaEllipsisV, FaPencilAlt, FaSignOutAlt, FaTrash, FaDownload, FaEye, + FaLink, } from 'react-icons/fa' +import { toast, Notification } from '@/components/ui' // import { Dropdown } from '@/components/ui' // Artık kullanmıyoruz import type { FileItem as FileItemType, FileActionMenuItem } from '@/types/fileManagement' +import { FILE_URL } from '@/constants/app.constant' export interface FileItemProps { item: FileItemType @@ -132,6 +134,7 @@ const FileItem = forwardRef((props, ref) => { } = props const [dropdownOpen, setDropdownOpen] = useState(false) + const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | null>(null) const handleClick = () => { onSelect?.(item) @@ -141,6 +144,32 @@ const FileItem = forwardRef((props, ref) => { onDoubleClick?.(item, e) } + const handleContextMenu = (e: React.MouseEvent) => { + e.preventDefault() + e.stopPropagation() + + // Only show context menu if there are actions available + if (actionMenuItems.length > 0) { + setContextMenuPosition({ x: e.clientX, y: e.clientY }) + setDropdownOpen(true) + } + } + + // Close context menu when clicking outside + useEffect(() => { + const handleClickOutside = () => { + if (dropdownOpen) { + setDropdownOpen(false) + setContextMenuPosition(null) + } + } + + if (dropdownOpen) { + document.addEventListener('click', handleClickOutside) + return () => document.removeEventListener('click', handleClickOutside) + } + }, [dropdownOpen]) + const handleCheckboxChange = (e: React.ChangeEvent) => { e.stopPropagation() // Prevent item selection when clicking checkbox onToggleSelect?.(item) @@ -173,6 +202,35 @@ const FileItem = forwardRef((props, ref) => { }, ] : []), + // Copy File URL - sadece dosyalar için + ...(item.type === 'file' + ? [ + { + key: 'copyUrl', + label: 'URL Kopyala', + icon: 'HiLink', + onClick: () => { + const fileUrl = FILE_URL(item.path, item.tenantId) + navigator.clipboard.writeText(fileUrl).then( + () => { + toast.push( + + Dosya URL'si panoya kopyalandı + , + ) + }, + () => { + toast.push( + + URL kopyalanamadı + , + ) + }, + ) + }, + }, + ] + : []), // Create Folder - sadece klasörler için ...(item.type === 'folder' && onCreateFolder ? [ @@ -221,18 +279,26 @@ const FileItem = forwardRef((props, ref) => { ] const dropdownList = ( -
+
{actionMenuItems.map((menuItem) => (
{ + onClick={(e) => { + e.stopPropagation() menuItem.onClick() setDropdownOpen(false) + setContextMenuPosition(null) }} > {menuItem.icon === 'HiFolderPlus' && ( @@ -242,6 +308,7 @@ const FileItem = forwardRef((props, ref) => { {menuItem.icon === 'HiArrowDownTray' && ( )} + {menuItem.icon === 'HiLink' && } {menuItem.icon === 'HiPencil' && } {menuItem.icon === 'HiArrowRightOnRectangle' && ( @@ -277,19 +344,21 @@ const FileItem = forwardRef((props, ref) => { if (viewMode === 'list') { return ( -
+ <> +
{/* File Name */}
{/* Checkbox */} @@ -364,24 +433,30 @@ const FileItem = forwardRef((props, ref) => {
+ + {/* Context Menu */} + {dropdownOpen && contextMenuPosition && dropdownList} + ) } // Grid view (varsayılan) return ( -
+ <> +
{/* Checkbox */} {!item.isReadOnly && (
@@ -442,6 +517,10 @@ const FileItem = forwardRef((props, ref) => { )}
+ + {/* Context Menu */} + {dropdownOpen && contextMenuPosition && dropdownList} + ) })