feat: add move functionality to DocumentList and FAQList for improved document management
This commit is contained in:
@@ -152,6 +152,7 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
const [moving, setMoving] = useState(false);
|
const [moving, setMoving] = useState(false);
|
||||||
const [bulkMoveOpen, setBulkMoveOpen] = useState(false);
|
const [bulkMoveOpen, setBulkMoveOpen] = useState(false);
|
||||||
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
||||||
|
const [moveTargetIds, setMoveTargetIds] = useState<number[]>([]);
|
||||||
const [contextMenuDocumentId, setContextMenuDocumentId] = useState<number | null>(null);
|
const [contextMenuDocumentId, setContextMenuDocumentId] = useState<number | null>(null);
|
||||||
const [selectedDirectoryId, setSelectedDirectoryId] = useState<number | null>(null);
|
const [selectedDirectoryId, setSelectedDirectoryId] = useState<number | null>(null);
|
||||||
const [actionLoadingMap, setActionLoadingMap] = useState<Record<number, { rebuildIndex: boolean; delete: boolean }>>({});
|
const [actionLoadingMap, setActionLoadingMap] = useState<Record<number, { rebuildIndex: boolean; delete: boolean }>>({});
|
||||||
@@ -272,6 +273,11 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
setSelectedIds(checked ? currentPageIds : []);
|
setSelectedIds(checked ? currentPageIds : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openMoveDialog(ids: number[]) {
|
||||||
|
setMoveTargetIds(ids);
|
||||||
|
setBulkMoveOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
const openCreateDialog = useCallback(() => {
|
const openCreateDialog = useCallback(() => {
|
||||||
setEditingItem(null);
|
setEditingItem(null);
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
@@ -373,7 +379,8 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleBatchMove(directoryId: number) {
|
async function handleBatchMove(directoryId: number) {
|
||||||
if (!knowledgeBaseId || selectedIds.length === 0) {
|
const ids = moveTargetIds.length > 0 ? moveTargetIds : selectedIds;
|
||||||
|
if (!knowledgeBaseId || ids.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setMoving(true);
|
setMoving(true);
|
||||||
@@ -381,10 +388,11 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
await batchMoveKnowledgeDocuments({
|
await batchMoveKnowledgeDocuments({
|
||||||
knowledgeBaseId,
|
knowledgeBaseId,
|
||||||
directoryId,
|
directoryId,
|
||||||
ids: selectedIds,
|
ids,
|
||||||
});
|
});
|
||||||
toast.success(t("knowledge.batchMoved", { count: selectedIds.length }));
|
toast.success(t("knowledge.batchMoved", { count: ids.length }));
|
||||||
setBulkMoveOpen(false);
|
setBulkMoveOpen(false);
|
||||||
|
setMoveTargetIds([]);
|
||||||
setSelectedIds([]);
|
setSelectedIds([]);
|
||||||
await loadData();
|
await loadData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -540,6 +548,10 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
<PencilIcon className="mr-2 size-3.5" />
|
<PencilIcon className="mr-2 size-3.5" />
|
||||||
{t("knowledge.edit")}
|
{t("knowledge.edit")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => openMoveDialog([item.id])}>
|
||||||
|
<FolderInputIcon className="mr-2 size-3.5" />
|
||||||
|
{t("knowledge.move")}
|
||||||
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => void handleBuildIndex(item)}>
|
<DropdownMenuItem onClick={() => void handleBuildIndex(item)}>
|
||||||
<WrenchIcon className="mr-2 size-3.5" />
|
<WrenchIcon className="mr-2 size-3.5" />
|
||||||
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
||||||
@@ -561,6 +573,10 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
<PencilIcon className="mr-2 size-3.5" />
|
<PencilIcon className="mr-2 size-3.5" />
|
||||||
{t("knowledge.edit")}
|
{t("knowledge.edit")}
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem onClick={() => openMoveDialog([item.id])}>
|
||||||
|
<FolderInputIcon className="mr-2 size-3.5" />
|
||||||
|
{t("knowledge.move")}
|
||||||
|
</ContextMenuItem>
|
||||||
<ContextMenuItem onClick={() => void handleBuildIndex(item)} disabled={actionLoadingMap[item.id]?.rebuildIndex}>
|
<ContextMenuItem onClick={() => void handleBuildIndex(item)} disabled={actionLoadingMap[item.id]?.rebuildIndex}>
|
||||||
<WrenchIcon className="mr-2 size-3.5" />
|
<WrenchIcon className="mr-2 size-3.5" />
|
||||||
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
||||||
@@ -626,6 +642,10 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
<PencilIcon className="mr-2 size-3.5" />
|
<PencilIcon className="mr-2 size-3.5" />
|
||||||
{t("knowledge.edit")}
|
{t("knowledge.edit")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => openMoveDialog([item.id])}>
|
||||||
|
<FolderInputIcon className="mr-2 size-3.5" />
|
||||||
|
{t("knowledge.move")}
|
||||||
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => void handleBuildIndex(item)}>
|
<DropdownMenuItem onClick={() => void handleBuildIndex(item)}>
|
||||||
<WrenchIcon className="mr-2 size-3.5" />
|
<WrenchIcon className="mr-2 size-3.5" />
|
||||||
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
||||||
@@ -646,6 +666,10 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
<PencilIcon className="mr-2 size-3.5" />
|
<PencilIcon className="mr-2 size-3.5" />
|
||||||
{t("knowledge.edit")}
|
{t("knowledge.edit")}
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem onClick={() => openMoveDialog([item.id])}>
|
||||||
|
<FolderInputIcon className="mr-2 size-3.5" />
|
||||||
|
{t("knowledge.move")}
|
||||||
|
</ContextMenuItem>
|
||||||
<ContextMenuItem onClick={() => void handleBuildIndex(item)} disabled={actionLoadingMap[item.id]?.rebuildIndex}>
|
<ContextMenuItem onClick={() => void handleBuildIndex(item)} disabled={actionLoadingMap[item.id]?.rebuildIndex}>
|
||||||
<WrenchIcon className="mr-2 size-3.5" />
|
<WrenchIcon className="mr-2 size-3.5" />
|
||||||
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
||||||
@@ -680,7 +704,7 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-7"
|
className="h-7"
|
||||||
onClick={() => setBulkMoveOpen(true)}
|
onClick={() => openMoveDialog(selectedIds)}
|
||||||
disabled={saving || moving}
|
disabled={saving || moving}
|
||||||
>
|
>
|
||||||
<FolderInputIcon className="size-3.5" />
|
<FolderInputIcon className="size-3.5" />
|
||||||
@@ -737,8 +761,13 @@ export function DocumentList({ knowledgeBaseId, onActionStateChange }: DocumentL
|
|||||||
open={bulkMoveOpen}
|
open={bulkMoveOpen}
|
||||||
knowledgeBaseId={knowledgeBaseId}
|
knowledgeBaseId={knowledgeBaseId}
|
||||||
moving={moving}
|
moving={moving}
|
||||||
selectedCount={selectedIds.length}
|
selectedCount={moveTargetIds.length || selectedIds.length}
|
||||||
onOpenChange={setBulkMoveOpen}
|
onOpenChange={(open) => {
|
||||||
|
setBulkMoveOpen(open);
|
||||||
|
if (!open) {
|
||||||
|
setMoveTargetIds([]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
onSubmit={(directoryId) => void handleBatchMove(directoryId)}
|
onSubmit={(directoryId) => void handleBatchMove(directoryId)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ export function FAQList({
|
|||||||
const [moving, setMoving] = useState(false);
|
const [moving, setMoving] = useState(false);
|
||||||
const [bulkMoveOpen, setBulkMoveOpen] = useState(false);
|
const [bulkMoveOpen, setBulkMoveOpen] = useState(false);
|
||||||
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
||||||
|
const [moveTargetIds, setMoveTargetIds] = useState<number[]>([]);
|
||||||
const [contextMenuFAQId, setContextMenuFAQId] = useState<number | null>(null);
|
const [contextMenuFAQId, setContextMenuFAQId] = useState<number | null>(null);
|
||||||
const [importing, setImporting] = useState(false);
|
const [importing, setImporting] = useState(false);
|
||||||
const [importDialogOpen, setImportDialogOpen] = useState(false);
|
const [importDialogOpen, setImportDialogOpen] = useState(false);
|
||||||
@@ -252,6 +253,11 @@ export function FAQList({
|
|||||||
setSelectedIds(checked ? currentPageIds : []);
|
setSelectedIds(checked ? currentPageIds : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openMoveDialog(ids: number[]) {
|
||||||
|
setMoveTargetIds(ids);
|
||||||
|
setBulkMoveOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
function openEditDialog(item: KnowledgeFAQ) {
|
function openEditDialog(item: KnowledgeFAQ) {
|
||||||
setEditingItem(item);
|
setEditingItem(item);
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
@@ -330,7 +336,8 @@ export function FAQList({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleBatchMove(directoryId: number) {
|
async function handleBatchMove(directoryId: number) {
|
||||||
if (!knowledgeBaseId || selectedIds.length === 0) {
|
const ids = moveTargetIds.length > 0 ? moveTargetIds : selectedIds;
|
||||||
|
if (!knowledgeBaseId || ids.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setMoving(true);
|
setMoving(true);
|
||||||
@@ -338,10 +345,11 @@ export function FAQList({
|
|||||||
await batchMoveKnowledgeFAQs({
|
await batchMoveKnowledgeFAQs({
|
||||||
knowledgeBaseId,
|
knowledgeBaseId,
|
||||||
directoryId,
|
directoryId,
|
||||||
ids: selectedIds,
|
ids,
|
||||||
});
|
});
|
||||||
toast.success(t("knowledge.batchMoved", { count: selectedIds.length }));
|
toast.success(t("knowledge.batchMoved", { count: ids.length }));
|
||||||
setBulkMoveOpen(false);
|
setBulkMoveOpen(false);
|
||||||
|
setMoveTargetIds([]);
|
||||||
setSelectedIds([]);
|
setSelectedIds([]);
|
||||||
await loadData();
|
await loadData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -471,6 +479,10 @@ export function FAQList({
|
|||||||
<PencilIcon className="mr-2 size-3.5" />
|
<PencilIcon className="mr-2 size-3.5" />
|
||||||
{t("knowledge.edit")}
|
{t("knowledge.edit")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => openMoveDialog([item.id])}>
|
||||||
|
<FolderInputIcon className="mr-2 size-3.5" />
|
||||||
|
{t("knowledge.move")}
|
||||||
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => void handleBuildIndex(item)}>
|
<DropdownMenuItem onClick={() => void handleBuildIndex(item)}>
|
||||||
<WrenchIcon className="mr-2 size-3.5" />
|
<WrenchIcon className="mr-2 size-3.5" />
|
||||||
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
||||||
@@ -491,6 +503,10 @@ export function FAQList({
|
|||||||
<PencilIcon className="mr-2 size-3.5" />
|
<PencilIcon className="mr-2 size-3.5" />
|
||||||
{t("knowledge.edit")}
|
{t("knowledge.edit")}
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem onClick={() => openMoveDialog([item.id])}>
|
||||||
|
<FolderInputIcon className="mr-2 size-3.5" />
|
||||||
|
{t("knowledge.move")}
|
||||||
|
</ContextMenuItem>
|
||||||
<ContextMenuItem onClick={() => void handleBuildIndex(item)} disabled={actionLoadingMap[item.id]?.rebuildIndex}>
|
<ContextMenuItem onClick={() => void handleBuildIndex(item)} disabled={actionLoadingMap[item.id]?.rebuildIndex}>
|
||||||
<WrenchIcon className="mr-2 size-3.5" />
|
<WrenchIcon className="mr-2 size-3.5" />
|
||||||
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
{actionLoadingMap[item.id]?.rebuildIndex ? t("knowledge.running") : t("knowledge.rebuildIndex")}
|
||||||
@@ -524,7 +540,7 @@ export function FAQList({
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-7"
|
className="h-7"
|
||||||
onClick={() => setBulkMoveOpen(true)}
|
onClick={() => openMoveDialog(selectedIds)}
|
||||||
disabled={saving || moving}
|
disabled={saving || moving}
|
||||||
>
|
>
|
||||||
<FolderInputIcon className="size-3.5" />
|
<FolderInputIcon className="size-3.5" />
|
||||||
@@ -593,8 +609,13 @@ export function FAQList({
|
|||||||
open={bulkMoveOpen}
|
open={bulkMoveOpen}
|
||||||
knowledgeBaseId={knowledgeBaseId}
|
knowledgeBaseId={knowledgeBaseId}
|
||||||
moving={moving}
|
moving={moving}
|
||||||
selectedCount={selectedIds.length}
|
selectedCount={moveTargetIds.length || selectedIds.length}
|
||||||
onOpenChange={setBulkMoveOpen}
|
onOpenChange={(open) => {
|
||||||
|
setBulkMoveOpen(open);
|
||||||
|
if (!open) {
|
||||||
|
setMoveTargetIds([]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
onSubmit={(directoryId) => void handleBatchMove(directoryId)}
|
onSubmit={(directoryId) => void handleBatchMove(directoryId)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user