fix(knowledge): repair folder reordering — wrong DAO method and card view left out

Two defects from the folder-ordering change, both from assuming the space-ordering
code carried over unchanged:

- reorder_folder called KnowledgeFileDao.aquery_by_id, which only exists on
  KnowledgeDao; KnowledgeFileDao names it query_by_id. Every drag returned a 500.
  Exercised end to end on a real directory this time: the first drag spreads the
  directory's weights (1000, 2000, ...) and the moved folder lands where it was
  dropped.
- The drag only reached the list view. Card view now drags the same folders, with the
  handlers on the grid wrapper so FileCard stays unaware of ordering; because cards
  flow left-to-right, the drop half-test and the insertion line are horizontal there.
This commit is contained in:
dolphin
2026-08-05 20:13:25 +08:00
parent 81592990bb
commit c9282edf1f
2 changed files with 66 additions and 2 deletions
@@ -11340,7 +11340,7 @@ class KnowledgeSpaceService(KnowledgeUtils):
if not self.login_user.is_admin():
raise SpacePermissionDeniedError()
folder = await KnowledgeFileDao.aquery_by_id(folder_id)
folder = await KnowledgeFileDao.query_by_id(folder_id)
if not folder or int(folder.knowledge_id) != int(space_id) or folder.file_type != FileType.DIR.value:
raise SpaceFolderNotFoundError()
@@ -33,6 +33,10 @@ import {
triggerUrlDownload,
} from "../knowledgeUtils";
import { bishengConfState } from "~/pages/appChat/store/atoms";
import {
resolveFolderReorderNeighbours,
type FolderDropPosition,
} from "./resolveFolderReorderNeighbours";
import store from "~/store";
import { SearchParams } from "./CompoundSearchInput";
import { EditTagsModal } from "./EditTagsModal";
@@ -906,6 +910,21 @@ export function KnowledgeSpaceContent({
const currentUser = useRecoilValue(store.user);
const isSystemAdmin = currentUser?.role === "admin";
// Card view drags the same folders as the list view; the grid wrapper carries the
// handlers so FileCard itself stays unaware of ordering.
const [cardDraggingFolderId, setCardDraggingFolderId] = useState<string | null>(null);
const [cardFolderDropTarget, setCardFolderDropTarget] = useState<{ id: string; position: FolderDropPosition } | null>(null);
const cardFolderReorderEnabled = isSystemAdmin && !sortBy;
const isCardDraggableFolder = useCallback((file: KnowledgeFile) => (
cardFolderReorderEnabled && file.type === FileType.FOLDER && !file.isCreating
), [cardFolderReorderEnabled]);
const handleCardFolderDragEnd = useCallback(() => {
setCardDraggingFolderId(null);
setCardFolderDropTarget(null);
}, []);
const handleReorderFolder = useCallback(async (
folderId: string,
prevFolderId: string | null,
@@ -1623,7 +1642,52 @@ export function KnowledgeSpaceContent({
}
>
{displayFiles.map((file) => (
<div key={file.id} data-knowledge-file-item>
<div
key={file.id}
data-knowledge-file-item
className={cn(
isCardDraggableFolder(file) && "cursor-grab",
cardDraggingFolderId === file.id && "opacity-50",
// Cards flow left-to-right, so the insertion line is vertical.
cardFolderDropTarget?.id === file.id && cardFolderDropTarget.position === "before"
&& "border-l-2 border-l-[#165dff]",
cardFolderDropTarget?.id === file.id && cardFolderDropTarget.position === "after"
&& "border-r-2 border-r-[#165dff]",
)}
draggable={isCardDraggableFolder(file) || undefined}
onDragStart={isCardDraggableFolder(file) ? () => setCardDraggingFolderId(file.id) : undefined}
onDragEnd={isCardDraggableFolder(file) ? handleCardFolderDragEnd : undefined}
onDragOver={isCardDraggableFolder(file) ? (event) => {
if (!cardDraggingFolderId || cardDraggingFolderId === file.id) return;
event.preventDefault();
event.dataTransfer.dropEffect = "move";
const bounds = event.currentTarget.getBoundingClientRect();
const position: FolderDropPosition =
event.clientX < bounds.left + bounds.width / 2 ? "before" : "after";
setCardFolderDropTarget((prev) => (
prev && prev.id === file.id && prev.position === position
? prev
: { id: file.id, position }
));
} : undefined}
onDragLeave={isCardDraggableFolder(file)
? () => setCardFolderDropTarget((prev) => (prev?.id === file.id ? null : prev))
: undefined}
onDrop={isCardDraggableFolder(file) ? (event) => {
event.preventDefault();
const dropPosition = cardFolderDropTarget?.id === file.id
? cardFolderDropTarget.position
: "before";
const draggedId = cardDraggingFolderId;
handleCardFolderDragEnd();
if (!draggedId) return;
const neighbours = resolveFolderReorderNeighbours(
displayFiles, draggedId, file.id, dropPosition,
);
if (!neighbours) return;
void handleReorderFolder(draggedId, neighbours.prevFolderId, neighbours.nextFolderId);
} : undefined}
>
<FileCard
file={file}
userRole={space.role}