mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-06-04 11:24:00 +08:00
### What problem does this PR solve? Feat: Rename a dataset #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
ad220a0a3c
commit
e7f83b13ca
@ -78,13 +78,15 @@ const DropdownMenuItem = React.forwardRef<
|
|||||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||||
inset?: boolean;
|
inset?: boolean;
|
||||||
|
justifyBetween?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, justifyBetween = true, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Item
|
<DropdownMenuPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||||
inset && 'pl-8',
|
inset && 'pl-8',
|
||||||
|
justifyBetween && 'flex justify-between',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -180,7 +180,7 @@ export const useDeleteKnowledge = () => {
|
|||||||
|
|
||||||
//#region knowledge configuration
|
//#region knowledge configuration
|
||||||
|
|
||||||
export const useUpdateKnowledge = () => {
|
export const useUpdateKnowledge = (shouldFetchList = false) => {
|
||||||
const knowledgeBaseId = useKnowledgeBaseId();
|
const knowledgeBaseId = useKnowledgeBaseId();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const {
|
const {
|
||||||
@ -191,12 +191,18 @@ export const useUpdateKnowledge = () => {
|
|||||||
mutationKey: ['saveKnowledge'],
|
mutationKey: ['saveKnowledge'],
|
||||||
mutationFn: async (params: Record<string, any>) => {
|
mutationFn: async (params: Record<string, any>) => {
|
||||||
const { data = {} } = await kbService.updateKb({
|
const { data = {} } = await kbService.updateKb({
|
||||||
kb_id: knowledgeBaseId,
|
kb_id: params?.kb_id ? params?.kb_id : knowledgeBaseId,
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
message.success(i18n.t(`message.updated`));
|
message.success(i18n.t(`message.updated`));
|
||||||
queryClient.invalidateQueries({ queryKey: ['fetchKnowledgeDetail'] });
|
if (shouldFetchList) {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ['infiniteFetchKnowledgeList'],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['fetchKnowledgeDetail'] });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
@ -23,7 +23,7 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
const FormId = 'dataset-creating-form';
|
const FormId = 'dataset-creating-form';
|
||||||
|
|
||||||
export function InputForm() {
|
export function InputForm({ onOk }: IModalProps<any>) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
@ -43,7 +43,7 @@ export function InputForm() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function onSubmit(data: z.infer<typeof FormSchema>) {
|
function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||||
console.log('🚀 ~ onSubmit ~ data:', data);
|
onOk?.(data.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -74,7 +74,7 @@ export function InputForm() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DatasetCreatingDialog({ hideModal }: IModalProps<any>) {
|
export function DatasetCreatingDialog({ hideModal, onOk }: IModalProps<any>) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -83,7 +83,7 @@ export function DatasetCreatingDialog({ hideModal }: IModalProps<any>) {
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{t('knowledgeList.createKnowledgeBase')}</DialogTitle>
|
<DialogTitle>{t('knowledgeList.createKnowledgeBase')}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<InputForm></InputForm>
|
<InputForm onOk={onOk}></InputForm>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button type="submit" variant={'tertiary'} size={'sm'} form={FormId}>
|
<Button type="submit" variant={'tertiary'} size={'sm'} form={FormId}>
|
||||||
{t('common.save')}
|
{t('common.save')}
|
||||||
|
54
web/src/pages/datasets/dataset-dropdown.tsx
Normal file
54
web/src/pages/datasets/dataset-dropdown.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import { useDeleteKnowledge } from '@/hooks/knowledge-hooks';
|
||||||
|
import { IKnowledge } from '@/interfaces/database/knowledge';
|
||||||
|
import { PenLine, Trash2 } from 'lucide-react';
|
||||||
|
import { PropsWithChildren, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useRenameDataset } from './use-rename-dataset';
|
||||||
|
|
||||||
|
export function DatasetDropdown({
|
||||||
|
children,
|
||||||
|
showDatasetRenameModal,
|
||||||
|
dataset,
|
||||||
|
}: PropsWithChildren &
|
||||||
|
Pick<ReturnType<typeof useRenameDataset>, 'showDatasetRenameModal'> & {
|
||||||
|
dataset: IKnowledge;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { deleteKnowledge } = useDeleteKnowledge();
|
||||||
|
|
||||||
|
const handleShowDatasetRenameModal = useCallback(() => {
|
||||||
|
showDatasetRenameModal(dataset);
|
||||||
|
}, [dataset, showDatasetRenameModal]);
|
||||||
|
|
||||||
|
const handleDelete = useCallback(() => {
|
||||||
|
deleteKnowledge(dataset.id);
|
||||||
|
}, [dataset.id, deleteKnowledge]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
<DropdownMenuItem onClick={handleShowDatasetRenameModal}>
|
||||||
|
{t('common.rename')} <PenLine />
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="text-text-delete-red"
|
||||||
|
onSelect={(e) => e.preventDefault()}
|
||||||
|
>
|
||||||
|
{t('common.delete')} <Trash2 />
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</ConfirmDeleteDialog>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
import { KnowledgeRouteKey } from '@/constants/knowledge';
|
|
||||||
import { useSetModalState } from '@/hooks/common-hooks';
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
import { useCreateKnowledge } from '@/hooks/knowledge-hooks';
|
import { useCreateKnowledge } from '@/hooks/knowledge-hooks';
|
||||||
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { useNavigate } from 'umi';
|
|
||||||
|
|
||||||
export const useSearchKnowledge = () => {
|
export const useSearchKnowledge = () => {
|
||||||
const [searchString, setSearchString] = useState<string>('');
|
const [searchString, setSearchString] = useState<string>('');
|
||||||
@ -19,7 +18,7 @@ export const useSearchKnowledge = () => {
|
|||||||
export const useSaveKnowledge = () => {
|
export const useSaveKnowledge = () => {
|
||||||
const { visible: visible, hideModal, showModal } = useSetModalState();
|
const { visible: visible, hideModal, showModal } = useSetModalState();
|
||||||
const { loading, createKnowledge } = useCreateKnowledge();
|
const { loading, createKnowledge } = useCreateKnowledge();
|
||||||
const navigate = useNavigate();
|
const { navigateToDataset } = useNavigatePage();
|
||||||
|
|
||||||
const onCreateOk = useCallback(
|
const onCreateOk = useCallback(
|
||||||
async (name: string) => {
|
async (name: string) => {
|
||||||
@ -29,12 +28,10 @@ export const useSaveKnowledge = () => {
|
|||||||
|
|
||||||
if (ret?.code === 0) {
|
if (ret?.code === 0) {
|
||||||
hideModal();
|
hideModal();
|
||||||
navigate(
|
navigateToDataset(ret.data.kb_id)();
|
||||||
`/knowledge/${KnowledgeRouteKey.Configuration}?id=${ret.data.kb_id}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[createKnowledge, hideModal, navigate],
|
[createKnowledge, hideModal, navigateToDataset],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
|
||||||
import ListFilterBar from '@/components/list-filter-bar';
|
import ListFilterBar from '@/components/list-filter-bar';
|
||||||
|
import { RenameDialog } from '@/components/rename-dialog';
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
@ -7,10 +7,12 @@ import { useInfiniteFetchKnowledgeList } from '@/hooks/knowledge-hooks';
|
|||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { IKnowledge } from '@/interfaces/database/knowledge';
|
import { IKnowledge } from '@/interfaces/database/knowledge';
|
||||||
import { formatDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import { ChevronRight, Plus, Trash2 } from 'lucide-react';
|
import { ChevronRight, Ellipsis, Plus } from 'lucide-react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { DatasetCreatingDialog } from './dataset-creating-dialog';
|
import { DatasetCreatingDialog } from './dataset-creating-dialog';
|
||||||
|
import { DatasetDropdown } from './dataset-dropdown';
|
||||||
import { useSaveKnowledge } from './hooks';
|
import { useSaveKnowledge } from './hooks';
|
||||||
|
import { useRenameDataset } from './use-rename-dataset';
|
||||||
|
|
||||||
export default function Datasets() {
|
export default function Datasets() {
|
||||||
const {
|
const {
|
||||||
@ -41,6 +43,15 @@ export default function Datasets() {
|
|||||||
return data?.pages.at(-1).total ?? 0;
|
return data?.pages.at(-1).total ?? 0;
|
||||||
}, [data?.pages]);
|
}, [data?.pages]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
datasetRenameLoading,
|
||||||
|
initialDatasetName,
|
||||||
|
onDatasetRenameOk,
|
||||||
|
datasetRenameVisible,
|
||||||
|
hideDatasetRenameModal,
|
||||||
|
showDatasetRenameModal,
|
||||||
|
} = useRenameDataset();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="p-8 text-foreground">
|
<section className="p-8 text-foreground">
|
||||||
<ListFilterBar title="Datasets" showDialog={showModal}>
|
<ListFilterBar title="Datasets" showDialog={showModal}>
|
||||||
@ -59,11 +70,14 @@ export default function Datasets() {
|
|||||||
<AvatarImage src={dataset.avatar} />
|
<AvatarImage src={dataset.avatar} />
|
||||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<ConfirmDeleteDialog>
|
<DatasetDropdown
|
||||||
|
showDatasetRenameModal={showDatasetRenameModal}
|
||||||
|
dataset={dataset}
|
||||||
|
>
|
||||||
<Button variant="ghost" size="icon">
|
<Button variant="ghost" size="icon">
|
||||||
<Trash2 />
|
<Ellipsis />
|
||||||
</Button>
|
</Button>
|
||||||
</ConfirmDeleteDialog>
|
</DatasetDropdown>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-end">
|
<div className="flex justify-between items-end">
|
||||||
<div>
|
<div>
|
||||||
@ -92,6 +106,14 @@ export default function Datasets() {
|
|||||||
loading={creatingLoading}
|
loading={creatingLoading}
|
||||||
></DatasetCreatingDialog>
|
></DatasetCreatingDialog>
|
||||||
)}
|
)}
|
||||||
|
{datasetRenameVisible && (
|
||||||
|
<RenameDialog
|
||||||
|
hideModal={hideDatasetRenameModal}
|
||||||
|
onOk={onDatasetRenameOk}
|
||||||
|
initialName={initialDatasetName}
|
||||||
|
loading={datasetRenameLoading}
|
||||||
|
></RenameDialog>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
47
web/src/pages/datasets/use-rename-dataset.ts
Normal file
47
web/src/pages/datasets/use-rename-dataset.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { useUpdateKnowledge } from '@/hooks/knowledge-hooks';
|
||||||
|
import { IKnowledge } from '@/interfaces/database/knowledge';
|
||||||
|
import { omit } from 'lodash';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
export const useRenameDataset = () => {
|
||||||
|
const [dataset, setDataset] = useState<IKnowledge>({} as IKnowledge);
|
||||||
|
const {
|
||||||
|
visible: datasetRenameVisible,
|
||||||
|
hideModal: hideDatasetRenameModal,
|
||||||
|
showModal: showDatasetRenameModal,
|
||||||
|
} = useSetModalState();
|
||||||
|
const { saveKnowledgeConfiguration, loading } = useUpdateKnowledge(true);
|
||||||
|
|
||||||
|
const onDatasetRenameOk = useCallback(
|
||||||
|
async (name: string) => {
|
||||||
|
const ret = await saveKnowledgeConfiguration({
|
||||||
|
...omit(dataset, ['id', 'update_time', 'nickname', 'tenant_avatar']),
|
||||||
|
kb_id: dataset.id,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ret.code === 0) {
|
||||||
|
hideDatasetRenameModal();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[saveKnowledgeConfiguration, dataset, hideDatasetRenameModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleShowDatasetRenameModal = useCallback(
|
||||||
|
async (record: IKnowledge) => {
|
||||||
|
setDataset(record);
|
||||||
|
showDatasetRenameModal();
|
||||||
|
},
|
||||||
|
[showDatasetRenameModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
datasetRenameLoading: loading,
|
||||||
|
initialDatasetName: dataset?.name,
|
||||||
|
onDatasetRenameOk,
|
||||||
|
datasetRenameVisible,
|
||||||
|
hideDatasetRenameModal,
|
||||||
|
showDatasetRenameModal: handleShowDatasetRenameModal,
|
||||||
|
};
|
||||||
|
};
|
@ -40,6 +40,7 @@ module.exports = {
|
|||||||
'colors-text-inverse-strong': 'var(--colors-text-inverse-strong)',
|
'colors-text-inverse-strong': 'var(--colors-text-inverse-strong)',
|
||||||
'colors-text-persist-light': 'var(--colors-text-persist-light)',
|
'colors-text-persist-light': 'var(--colors-text-persist-light)',
|
||||||
'colors-text-inverse-weak': 'var(--colors-text-inverse-weak)',
|
'colors-text-inverse-weak': 'var(--colors-text-inverse-weak)',
|
||||||
|
'text-delete-red': 'var(--text-delete-red)',
|
||||||
|
|
||||||
primary: {
|
primary: {
|
||||||
DEFAULT: 'hsl(var(--primary))',
|
DEFAULT: 'hsl(var(--primary))',
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
--colors-text-inverse-strong: rgba(255, 255, 255, 1);
|
--colors-text-inverse-strong: rgba(255, 255, 255, 1);
|
||||||
--colors-text-persist-light: rgba(255, 255, 255, 1);
|
--colors-text-persist-light: rgba(255, 255, 255, 1);
|
||||||
--colors-text-inverse-weak: rgba(184, 181, 203, 1);
|
--colors-text-inverse-weak: rgba(184, 181, 203, 1);
|
||||||
|
--text-delete-red: rgba(216, 73, 75, 1);
|
||||||
|
|
||||||
--sidebar-background: 0 0% 98%;
|
--sidebar-background: 0 0% 98%;
|
||||||
--sidebar-foreground: 240 5.3% 26.1%;
|
--sidebar-foreground: 240 5.3% 26.1%;
|
||||||
@ -153,6 +154,7 @@
|
|||||||
--colors-text-inverse-strong: rgba(17, 16, 23, 1);
|
--colors-text-inverse-strong: rgba(17, 16, 23, 1);
|
||||||
--colors-text-persist-light: rgba(255, 255, 255, 1);
|
--colors-text-persist-light: rgba(255, 255, 255, 1);
|
||||||
--colors-text-inverse-weak: rgba(84, 80, 106, 1);
|
--colors-text-inverse-weak: rgba(84, 80, 106, 1);
|
||||||
|
--text-delete-red: rgba(216, 73, 75, 1);
|
||||||
|
|
||||||
--sidebar-background: 240 5.9% 10%;
|
--sidebar-background: 240 5.9% 10%;
|
||||||
--sidebar-foreground: 240 4.8% 95.9%;
|
--sidebar-foreground: 240 4.8% 95.9%;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user