Browse Source

Feat: Rename a dataset #3221 (#7162)

### What problem does this PR solve?

Feat: Rename a dataset #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.18.0
balibabu 6 months ago
parent
commit
e7f83b13ca
No account linked to committer's email address

+ 3
- 1
web/src/components/ui/dropdown-menu.tsx View File

@@ -78,13 +78,15 @@ const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean;
justifyBetween?: boolean;
}
>(({ className, inset, ...props }, ref) => (
>(({ className, inset, justifyBetween = true, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
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',
inset && 'pl-8',
justifyBetween && 'flex justify-between',
className,
)}
{...props}

+ 9
- 3
web/src/hooks/knowledge-hooks.ts View File

@@ -180,7 +180,7 @@ export const useDeleteKnowledge = () => {

//#region knowledge configuration

export const useUpdateKnowledge = () => {
export const useUpdateKnowledge = (shouldFetchList = false) => {
const knowledgeBaseId = useKnowledgeBaseId();
const queryClient = useQueryClient();
const {
@@ -191,12 +191,18 @@ export const useUpdateKnowledge = () => {
mutationKey: ['saveKnowledge'],
mutationFn: async (params: Record<string, any>) => {
const { data = {} } = await kbService.updateKb({
kb_id: knowledgeBaseId,
kb_id: params?.kb_id ? params?.kb_id : knowledgeBaseId,
...params,
});
if (data.code === 0) {
message.success(i18n.t(`message.updated`));
queryClient.invalidateQueries({ queryKey: ['fetchKnowledgeDetail'] });
if (shouldFetchList) {
queryClient.invalidateQueries({
queryKey: ['infiniteFetchKnowledgeList'],
});
} else {
queryClient.invalidateQueries({ queryKey: ['fetchKnowledgeDetail'] });
}
}
return data;
},

+ 4
- 4
web/src/pages/datasets/dataset-creating-dialog.tsx View File

@@ -23,7 +23,7 @@ import { z } from 'zod';

const FormId = 'dataset-creating-form';

export function InputForm() {
export function InputForm({ onOk }: IModalProps<any>) {
const { t } = useTranslation();

const FormSchema = z.object({
@@ -43,7 +43,7 @@ export function InputForm() {
});

function onSubmit(data: z.infer<typeof FormSchema>) {
console.log('🚀 ~ onSubmit ~ data:', data);
onOk?.(data.name);
}

return (
@@ -74,7 +74,7 @@ export function InputForm() {
);
}

export function DatasetCreatingDialog({ hideModal }: IModalProps<any>) {
export function DatasetCreatingDialog({ hideModal, onOk }: IModalProps<any>) {
const { t } = useTranslation();

return (
@@ -83,7 +83,7 @@ export function DatasetCreatingDialog({ hideModal }: IModalProps<any>) {
<DialogHeader>
<DialogTitle>{t('knowledgeList.createKnowledgeBase')}</DialogTitle>
</DialogHeader>
<InputForm></InputForm>
<InputForm onOk={onOk}></InputForm>
<DialogFooter>
<Button type="submit" variant={'tertiary'} size={'sm'} form={FormId}>
{t('common.save')}

+ 54
- 0
web/src/pages/datasets/dataset-dropdown.tsx View 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>
);
}

+ 4
- 7
web/src/pages/datasets/hooks.ts View File

@@ -1,8 +1,7 @@
import { KnowledgeRouteKey } from '@/constants/knowledge';
import { useSetModalState } from '@/hooks/common-hooks';
import { useCreateKnowledge } from '@/hooks/knowledge-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useCallback, useState } from 'react';
import { useNavigate } from 'umi';

export const useSearchKnowledge = () => {
const [searchString, setSearchString] = useState<string>('');
@@ -19,7 +18,7 @@ export const useSearchKnowledge = () => {
export const useSaveKnowledge = () => {
const { visible: visible, hideModal, showModal } = useSetModalState();
const { loading, createKnowledge } = useCreateKnowledge();
const navigate = useNavigate();
const { navigateToDataset } = useNavigatePage();

const onCreateOk = useCallback(
async (name: string) => {
@@ -29,12 +28,10 @@ export const useSaveKnowledge = () => {

if (ret?.code === 0) {
hideModal();
navigate(
`/knowledge/${KnowledgeRouteKey.Configuration}?id=${ret.data.kb_id}`,
);
navigateToDataset(ret.data.kb_id)();
}
},
[createKnowledge, hideModal, navigate],
[createKnowledge, hideModal, navigateToDataset],
);

return {

+ 27
- 5
web/src/pages/datasets/index.tsx View File

@@ -1,5 +1,5 @@
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
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 { IKnowledge } from '@/interfaces/database/knowledge';
import { formatDate } from '@/utils/date';
import { ChevronRight, Plus, Trash2 } from 'lucide-react';
import { ChevronRight, Ellipsis, Plus } from 'lucide-react';
import { useMemo } from 'react';
import { DatasetCreatingDialog } from './dataset-creating-dialog';
import { DatasetDropdown } from './dataset-dropdown';
import { useSaveKnowledge } from './hooks';
import { useRenameDataset } from './use-rename-dataset';

export default function Datasets() {
const {
@@ -41,6 +43,15 @@ export default function Datasets() {
return data?.pages.at(-1).total ?? 0;
}, [data?.pages]);

const {
datasetRenameLoading,
initialDatasetName,
onDatasetRenameOk,
datasetRenameVisible,
hideDatasetRenameModal,
showDatasetRenameModal,
} = useRenameDataset();

return (
<section className="p-8 text-foreground">
<ListFilterBar title="Datasets" showDialog={showModal}>
@@ -59,11 +70,14 @@ export default function Datasets() {
<AvatarImage src={dataset.avatar} />
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
</Avatar>
<ConfirmDeleteDialog>
<DatasetDropdown
showDatasetRenameModal={showDatasetRenameModal}
dataset={dataset}
>
<Button variant="ghost" size="icon">
<Trash2 />
<Ellipsis />
</Button>
</ConfirmDeleteDialog>
</DatasetDropdown>
</div>
<div className="flex justify-between items-end">
<div>
@@ -92,6 +106,14 @@ export default function Datasets() {
loading={creatingLoading}
></DatasetCreatingDialog>
)}
{datasetRenameVisible && (
<RenameDialog
hideModal={hideDatasetRenameModal}
onOk={onDatasetRenameOk}
initialName={initialDatasetName}
loading={datasetRenameLoading}
></RenameDialog>
)}
</section>
);
}

+ 47
- 0
web/src/pages/datasets/use-rename-dataset.ts View 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,
};
};

+ 1
- 0
web/tailwind.config.js View File

@@ -40,6 +40,7 @@ module.exports = {
'colors-text-inverse-strong': 'var(--colors-text-inverse-strong)',
'colors-text-persist-light': 'var(--colors-text-persist-light)',
'colors-text-inverse-weak': 'var(--colors-text-inverse-weak)',
'text-delete-red': 'var(--text-delete-red)',

primary: {
DEFAULT: 'hsl(var(--primary))',

+ 2
- 0
web/tailwind.css View File

@@ -61,6 +61,7 @@
--colors-text-inverse-strong: rgba(255, 255, 255, 1);
--colors-text-persist-light: rgba(255, 255, 255, 1);
--colors-text-inverse-weak: rgba(184, 181, 203, 1);
--text-delete-red: rgba(216, 73, 75, 1);

--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
@@ -153,6 +154,7 @@
--colors-text-inverse-strong: rgba(17, 16, 23, 1);
--colors-text-persist-light: rgba(255, 255, 255, 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-foreground: 240 4.8% 95.9%;

Loading…
Cancel
Save