DMS redesign: 3-column explorer layout with toolbar, source tree, file details panel

- Add backend endpoints: GET /dms/files, GET /dms/folders/{id}/files
- New SourceTree component: sources (Meine Dateien, Geteilte Ordner, Externe Speicher)
- New FileExplorer component: 5 view modes (list, table, icons-sm/md/lg)
- New FileDetails component: right panel with file metadata and actions
- Rewrite Dms.tsx: PluginToolbar + 3-column ResizablePanel layout
- Update DmsFile type: size_bytes + uploaded_by (backward compat aliases)
- Add 60+ i18n keys for de/en
This commit is contained in:
Agent Zero
2026-07-20 17:31:04 +02:00
parent e1a9a8e33e
commit e94e64ba6b
11 changed files with 1641 additions and 143 deletions
+78
View File
@@ -502,6 +502,84 @@ async def get_file(
}
@router.get("/files")
async def list_all_files(
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List all non-deleted files for the current tenant."""
tenant_id = uuid.UUID(current_user["tenant_id"])
result = await db.execute(
select(DmsFile).where(
DmsFile.tenant_id == tenant_id,
DmsFile.deleted_at.is_(None),
)
)
files = result.scalars().all()
return [
{
"id": str(f.id),
"name": f.name,
"folder_id": str(f.folder_id) if f.folder_id else None,
"uploaded_by": str(f.uploaded_by),
"mime_type": f.mime_type,
"size_bytes": f.size_bytes,
"deleted_at": None,
"created_at": f.created_at.isoformat() if f.created_at else None,
"updated_at": f.updated_at.isoformat() if f.updated_at else None,
}
for f in files
]
@router.get("/folders/{folder_id}/files")
async def list_files_in_folder(
folder_id: str,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List all non-deleted files in a specific folder (non-recursive)."""
tenant_id = uuid.UUID(current_user["tenant_id"])
fid = _parse_uuid(folder_id, "folder_id")
# Validate folder exists
folder_result = await db.execute(
select(Folder).where(
Folder.id == fid,
Folder.tenant_id == tenant_id,
Folder.deleted_at.is_(None),
)
)
if folder_result.scalar_one_or_none() is None:
raise HTTPException(404, detail={"detail": "Folder not found", "code": "not_found"})
result = await db.execute(
select(DmsFile).where(
DmsFile.tenant_id == tenant_id,
DmsFile.folder_id == fid,
DmsFile.deleted_at.is_(None),
)
)
files = result.scalars().all()
return [
{
"id": str(f.id),
"name": f.name,
"folder_id": str(f.folder_id) if f.folder_id else None,
"uploaded_by": str(f.uploaded_by),
"mime_type": f.mime_type,
"size_bytes": f.size_bytes,
"deleted_at": None,
"created_at": f.created_at.isoformat() if f.created_at else None,
"updated_at": f.updated_at.isoformat() if f.updated_at else None,
}
for f in files
]
@router.patch("/files/{file_id}")
async def update_file(
file_id: str,