Fix: Bug fixes (#11960)

### What problem does this PR solve?

Fix: Bug fixes

New search popup style modification
Fixed multilingual settings not updating immediately on personal center
page
Changed overlapped percent to percentage format, with maximum value of
30%
### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
chanx
2025-12-16 09:44:06 +08:00
committed by GitHub
parent 7ca3e11566
commit a98887d4ca
19 changed files with 192 additions and 137 deletions

View File

@ -11,6 +11,7 @@ import {
DefaultValues,
FieldValues,
SubmitHandler,
UseFormTrigger,
useForm,
useFormContext,
} from 'react-hook-form';
@ -99,8 +100,9 @@ interface DynamicFormProps<T extends FieldValues> {
// Form ref interface
export interface DynamicFormRef {
submit: () => void;
getValues: () => any;
getValues: (name?: string) => any;
reset: (values?: any) => void;
trigger: UseFormTrigger<any>;
watch: (field: string, callback: (value: any) => void) => () => void;
updateFieldType: (fieldName: string, newType: FormFieldType) => void;
onFieldUpdate: (
@ -704,8 +706,8 @@ const DynamicForm = {
useImperativeHandle(
ref,
() => ({
submit: () => form.handleSubmit(onSubmit)(),
getValues: () => form.getValues(),
submit: form.handleSubmit,
getValues: form.getValues,
reset: (values?: T) => {
if (values) {
form.reset(values);

View File

@ -26,6 +26,7 @@ type SliderInputFormFieldProps = {
defaultValue?: number;
className?: string;
numberInputClassName?: string;
percentage?: boolean;
} & FormLayoutType;
export function SliderInputFormField({
@ -39,11 +40,14 @@ export function SliderInputFormField({
className,
numberInputClassName,
layout = FormLayout.Horizontal,
percentage = false,
}: SliderInputFormFieldProps) {
const form = useFormContext();
const isHorizontal = useMemo(() => layout !== FormLayout.Vertical, [layout]);
const displayMax = percentage ? (max || 1) * 100 : max;
const displayMin = percentage ? (min || 0) * 100 : min;
const displayStep = percentage ? (step || 0.01) * 100 : step;
return (
<FormField
control={form.control}
@ -71,12 +75,13 @@ export function SliderInputFormField({
<FormControl>
<SingleFormSlider
{...field}
max={max}
min={min}
step={step}
// defaultValue={
// typeof defaultValue === 'number' ? [defaultValue] : undefined
// }
value={percentage ? field.value * 100 : field.value}
onChange={(value) =>
field.onChange(percentage ? value / 100 : value)
}
max={displayMax}
min={displayMin}
step={displayStep}
></SingleFormSlider>
</FormControl>
<FormControl>
@ -86,11 +91,20 @@ export function SliderInputFormField({
'[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none',
numberInputClassName,
)}
max={max}
min={min}
step={step}
{...field}
// defaultValue={defaultValue}
max={displayMax}
min={displayMin}
step={displayStep}
value={
percentage ? (field.value * 100).toFixed(0) : field.value
}
onChange={(val) => {
const value = Number(val || 0);
if (!isNaN(value)) {
field.onChange(
percentage ? (value / 100).toFixed(0) : value,
);
}
}}
></NumberInput>
</FormControl>
</div>

View File

@ -174,20 +174,23 @@ const Modal: ModalType = ({
onClick={() => maskClosable && onOpenChange?.(false)}
>
<DialogPrimitive.Content
className={`relative w-[700px] ${full ? 'max-w-full' : sizeClasses[size]} ${className} bg-bg-base rounded-lg shadow-lg border border-border-default transition-all focus-visible:!outline-none`}
className={cn(
`relative w-[700px] ${full ? 'max-w-full' : sizeClasses[size]} ${className} bg-bg-base rounded-lg shadow-lg border border-border-default transition-all focus-visible:!outline-none`,
{ 'pt-10': closable && !title },
)}
style={style}
onClick={(e) => e.stopPropagation()}
>
{/* title */}
{(title || closable) && (
{title && (
<div
className={cn(
'flex items-start px-6 py-4',
{
'justify-end': closable && !title,
'justify-between': closable && title,
'justify-start': !closable,
},
'flex items-start px-6 py-4 justify-start',
// {
// 'justify-end': closable && !title,
// 'justify-between': closable && title,
// 'justify-start': !closable,
// },
titleClassName,
)}
>
@ -196,19 +199,19 @@ const Modal: ModalType = ({
{title}
</DialogPrimitive.Title>
)}
{closable && (
<DialogPrimitive.Close asChild>
<button
type="button"
className="flex h-7 w-7 items-center justify-center text-text-secondary rounded-full hover:text-text-primary focus-visible:outline-none"
onClick={handleCancel}
>
{closeIcon}
</button>
</DialogPrimitive.Close>
)}
</div>
)}
{closable && (
<DialogPrimitive.Close asChild>
<button
type="button"
className="flex absolute right-5 top-5 h-7 w-7 items-center justify-center text-text-secondary rounded-full hover:text-text-primary focus-visible:outline-none"
onClick={handleCancel}
>
{closeIcon}
</button>
</DialogPrimitive.Close>
)}
{/* content */}
<div className="py-2 px-6 overflow-y-auto scrollbar-auto max-h-[calc(100vh-280px)] focus-visible:!outline-none">

View File

@ -159,6 +159,7 @@ export default {
doc: 'Docs',
searchKnowledgePlaceholder: 'Search',
noMoreData: `That's all. Nothing more.`,
parserRequired: 'Chunk method is required',
},
knowledgeDetails: {
localUpload: 'Local upload',
@ -329,7 +330,7 @@ export default {
reRankModelWaring: 'Re-rank model is very time consuming.',
},
knowledgeConfiguration: {
overlappedPercent: 'Overlapped percent',
overlappedPercent: 'Overlapped percent(%)',
generationScopeTip:
'Determines whether RAPTOR is generated for the entire dataset or for a single file.',
scopeDataset: 'Dataset',

View File

@ -101,6 +101,7 @@ export default {
doc: '文档',
searchKnowledgePlaceholder: '搜索',
noMoreData: '没有更多数据了',
parserRequired: '分块方法必填',
},
knowledgeDetails: {
localUpload: '本地上传',

View File

@ -24,7 +24,8 @@ import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { cn } from '@/lib/utils';
import { PipelineResultSearchParams } from '@/pages/dataflow-result/constant';
import { NavigateToDataflowResultProps } from '@/pages/dataflow-result/interface';
import { DataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { useDataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { IDataSourceInfoMap } from '@/pages/user-setting/data-source/interface';
import { formatDate, formatSecondsToHumanReadable } from '@/utils/date';
import {
ColumnDef,
@ -54,6 +55,7 @@ export const getFileLogsTableColumns = (
navigateToDataflowResult: (
props: NavigateToDataflowResultProps,
) => () => void,
dataSourceInfo: IDataSourceInfoMap,
) => {
// const { t } = useTranslate('knowledgeDetails');
const columns: ColumnDef<IFileLogItem & DocumentLog>[] = [
@ -117,8 +119,8 @@ export const getFileLogsTableColumns = (
) : (
<div className="w-6 h-6 flex items-center justify-center">
{
DataSourceInfo[
row.original.source_from as keyof typeof DataSourceInfo
dataSourceInfo[
row.original.source_from as keyof typeof dataSourceInfo
].icon
}
</div>
@ -368,7 +370,7 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
setLogInfo(logDetail);
setIsModalVisible(true);
};
const { dataSourceInfo } = useDataSourceInfo();
const columns = useMemo(() => {
return active === LogTabs.FILE_LOGS
? getFileLogsTableColumns(
@ -376,6 +378,7 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
showLog,
kowledgeId || '',
navigateToDataflowResult,
dataSourceInfo,
)
: getDatasetLogsTableColumns(t, showLog);
}, [active, t]);

View File

@ -9,7 +9,7 @@ import {
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { IConnector } from '@/interfaces/database/knowledge';
import { delSourceModal } from '@/pages/user-setting/data-source/component/delete-source-modal';
import { DataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { useDataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { useDataSourceRebuild } from '@/pages/user-setting/data-source/hooks';
import { IDataSourceBase } from '@/pages/user-setting/data-source/interface';
import { Link, Settings, Unlink } from 'lucide-react';
@ -41,6 +41,7 @@ interface DataSourceItemProps extends IDataSourceNodeProps {
}
const DataSourceItem = (props: DataSourceItemProps) => {
const { dataSourceInfo } = useDataSourceInfo();
const { t } = useTranslation();
const { id, name, icon, source, auto_parse, unbindFunc, handleAutoParse } =
props;
@ -56,7 +57,7 @@ const DataSourceItem = (props: DataSourceItemProps) => {
<div className="flex items-center gap-1">
<div className="w-6 h-6 flex-shrink-0">{icon}</div>
<div className="text-base text-text-primary">
{DataSourceInfo[source].name}
{dataSourceInfo[source].name}
</div>
<div>{name}</div>
</div>
@ -114,6 +115,7 @@ const DataSourceItem = (props: DataSourceItemProps) => {
delSourceModal({
data: props,
type: 'unlink',
dataSourceInfo: dataSourceInfo,
onOk: (data) => unbindFunc?.(data as DataSourceItemProps),
});
}}
@ -134,6 +136,7 @@ const LinkDataSource = (props: ILinkDataSourceProps) => {
handleAutoParse,
} = props;
const { t } = useTranslation();
const { dataSourceInfo } = useDataSourceInfo();
const [openLinkModal, setOpenLinkModal] = useState(false);
const pipelineNode: IDataSourceNodeProps[] = useMemo(() => {
@ -144,7 +147,7 @@ const LinkDataSource = (props: ILinkDataSourceProps) => {
id: item?.id,
name: item?.name,
icon:
DataSourceInfo[item?.source as keyof typeof DataSourceInfo]?.icon ||
dataSourceInfo[item?.source as keyof typeof dataSourceInfo]?.icon ||
'',
} as IDataSourceNodeProps;
});

View File

@ -291,9 +291,10 @@ export function EnableTocToggle() {
export function OverlappedPercent() {
return (
<SliderInputFormField
percentage={true}
name="parser_config.overlapped_percent"
label={t('knowledgeConfiguration.overlappedPercent')}
max={0.5}
max={0.3}
step={0.01}
></SliderInputFormField>
);

View File

@ -8,7 +8,7 @@ import { FormLayout } from '@/constants/form';
import { DocumentParserType } from '@/constants/knowledge';
import { PermissionRole } from '@/constants/permission';
import { IConnector } from '@/interfaces/database/knowledge';
import { DataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { useDataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { IDataSourceBase } from '@/pages/user-setting/data-source/interface';
import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect, useState } from 'react';
@ -89,6 +89,7 @@ export default function DatasetSettings() {
connectors: [],
},
});
const { dataSourceInfo } = useDataSourceInfo();
const knowledgeDetails = useFetchKnowledgeConfigurationOnMount(form);
// const [pipelineData, setPipelineData] = useState<IDataPipelineNodeProps>();
const [sourceData, setSourceData] = useState<IDataSourceNodeProps[]>();
@ -113,7 +114,7 @@ export default function DatasetSettings() {
return {
...connector,
icon:
DataSourceInfo[connector.source as keyof typeof DataSourceInfo]
dataSourceInfo[connector.source as keyof typeof dataSourceInfo]
?.icon || '',
};
});
@ -159,7 +160,7 @@ export default function DatasetSettings() {
...connector,
auto_parse: connector.auto_parse === '0' ? '0' : '1',
icon:
DataSourceInfo[connector.source as keyof typeof DataSourceInfo]
dataSourceInfo[connector.source as keyof typeof dataSourceInfo]
?.icon || '',
};
});

View File

@ -11,7 +11,7 @@ import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useSetDocumentStatus } from '@/hooks/use-document-request';
import { IDocumentInfo } from '@/interfaces/database/document';
import { cn } from '@/lib/utils';
import { DataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { useDataSourceInfo } from '@/pages/user-setting/data-source/contant';
import { formatDate } from '@/utils/date';
import { ColumnDef } from '@tanstack/table-core';
import { ArrowUpDown, MonitorUp } from 'lucide-react';
@ -35,7 +35,7 @@ export function useDatasetTableColumns({
const { t } = useTranslation('translation', {
keyPrefix: 'knowledgeDetails',
});
const { dataSourceInfo } = useDataSourceInfo();
const { navigateToChunkParsedResult } = useNavigatePage();
const { setDocumentStatus } = useSetDocumentStatus();
@ -134,8 +134,8 @@ export function useDatasetTableColumns({
) : (
<div className="w-6 h-6 flex items-center justify-center">
{
DataSourceInfo[
row.original.source_type as keyof typeof DataSourceInfo
dataSourceInfo[
row.original.source_type as keyof typeof dataSourceInfo
]?.icon
}
</div>

View File

@ -1,7 +1,6 @@
import { CardContainer } from '@/components/card-container';
import { EmptyCardType } from '@/components/empty/constant';
import { EmptyAppCard } from '@/components/empty/empty';
import { IconFont } from '@/components/icon-font';
import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog';
import { Button } from '@/components/ui/button';
@ -149,7 +148,7 @@ export default function SearchList() {
onOk={onSearchRenameConfirm}
initialName={initialSearchName}
loading={searchRenameLoading}
title={<IconFont name="search" className="size-6"></IconFont>}
title={initialSearchName || t('createSearch')}
></RenameDialog>
)}
</section>

View File

@ -2,6 +2,7 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { Settings, Trash2 } from 'lucide-react';
import { useDataSourceInfo } from '../contant';
import { useDeleteDataSource } from '../hooks';
import { IDataSorceInfo, IDataSourceBase } from '../interface';
import { delSourceModal } from './delete-source-modal';
@ -13,6 +14,7 @@ export const AddedSourceCard = (props: IAddedSourceCardProps) => {
const { list, name, icon } = props;
const { handleDelete } = useDeleteDataSource();
const { navigateToDataSourceDetail } = useNavigatePage();
const { dataSourceInfo } = useDataSourceInfo();
const toDetail = (id: string) => {
navigateToDataSourceDetail(id);
};
@ -49,6 +51,7 @@ export const AddedSourceCard = (props: IAddedSourceCardProps) => {
onClick={() =>
delSourceModal({
data: item,
dataSourceInfo: dataSourceInfo,
onOk: () => {
handleDelete(item);
},

View File

@ -1,20 +1,19 @@
import { Button } from '@/components/ui/button';
import { Modal, ModalType } from '@/components/ui/modal/modal';
import { t } from 'i18next';
import { DataSourceInfo } from '../contant';
import { IDataSourceBase } from '../interface';
import { IDataSourceBase, IDataSourceInfoMap } from '../interface';
export type IDelSourceModalProps<T> = Partial<ModalType> & {
data?: T;
type?: 'delete' | 'unlink';
onOk?: (data?: T) => void;
dataSourceInfo: IDataSourceInfoMap;
};
export const delSourceModal = <T extends IDataSourceBase>(
props: IDelSourceModalProps<T>,
) => {
const { data, onOk, type = 'delete', ...otherProps } = props;
console.log('data', data);
const { data, onOk, type = 'delete', dataSourceInfo, ...otherProps } = props;
const config = {
title:
type === 'delete'
@ -39,7 +38,7 @@ export const delSourceModal = <T extends IDataSourceBase>(
)}
<div className="flex items-center gap-1 p-2 border border-border-button rounded-md mb-3">
<div className="w-6 h-6 flex-shrink-0">
{data?.source ? DataSourceInfo[data?.source].icon : ''}
{data?.source ? dataSourceInfo[data?.source].icon : ''}
</div>
<div className="flex items-center gap-2 text-text-secondary text-xs">
{/* <div className="h-6 flex-shrink-0 text-text-primary text-base">

View File

@ -1,11 +1,13 @@
import { FormFieldType } from '@/components/dynamic-form';
import SvgIcon from '@/components/svg-icon';
import { t } from 'i18next';
import { t, TFunction } from 'i18next';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import BoxTokenField from './component/box-token-field';
import { ConfluenceIndexingModeField } from './component/confluence-token-field';
import GmailTokenField from './component/gmail-token-field';
import GoogleDriveTokenField from './component/google-drive-token-field';
import { IDataSourceInfoMap } from './interface';
export enum DataSourceKey {
CONFLUENCE = 'confluence',
S3 = 's3',
@ -23,62 +25,75 @@ export enum DataSourceKey {
// TEAMS = 'teams',
}
export const DataSourceInfo = {
[DataSourceKey.S3]: {
name: 'S3',
description: t(`setting.${DataSourceKey.S3}Description`),
icon: <SvgIcon name={'data-source/s3'} width={38} />,
},
[DataSourceKey.NOTION]: {
name: 'Notion',
description: t(`setting.${DataSourceKey.NOTION}Description`),
icon: <SvgIcon name={'data-source/notion'} width={38} />,
},
[DataSourceKey.DISCORD]: {
name: 'Discord',
description: t(`setting.${DataSourceKey.DISCORD}Description`),
icon: <SvgIcon name={'data-source/discord'} width={38} />,
},
[DataSourceKey.CONFLUENCE]: {
name: 'Confluence',
description: t(`setting.${DataSourceKey.CONFLUENCE}Description`),
icon: <SvgIcon name={'data-source/confluence'} width={38} />,
},
[DataSourceKey.GOOGLE_DRIVE]: {
name: 'Google Drive',
description: t(`setting.${DataSourceKey.GOOGLE_DRIVE}Description`),
icon: <SvgIcon name={'data-source/google-drive'} width={38} />,
},
[DataSourceKey.GMAIL]: {
name: 'Gmail',
description: t(`setting.${DataSourceKey.GMAIL}Description`),
icon: <SvgIcon name={'data-source/gmail'} width={38} />,
},
[DataSourceKey.MOODLE]: {
name: 'Moodle',
description: t(`setting.${DataSourceKey.MOODLE}Description`),
icon: <SvgIcon name={'data-source/moodle'} width={38} />,
},
[DataSourceKey.JIRA]: {
name: 'Jira',
description: t(`setting.${DataSourceKey.JIRA}Description`),
icon: <SvgIcon name={'data-source/jira'} width={38} />,
},
[DataSourceKey.WEBDAV]: {
name: 'WebDAV',
description: t(`setting.${DataSourceKey.WEBDAV}Description`),
icon: <SvgIcon name={'data-source/webdav'} width={38} />,
},
[DataSourceKey.DROPBOX]: {
name: 'Dropbox',
description: t(`setting.${DataSourceKey.DROPBOX}Description`),
icon: <SvgIcon name={'data-source/dropbox'} width={38} />,
},
[DataSourceKey.BOX]: {
name: 'Box',
description: t(`setting.${DataSourceKey.BOX}Description`),
icon: <SvgIcon name={'data-source/box'} width={38} />,
},
export const generateDataSourceInfo = (t: TFunction) => {
return {
[DataSourceKey.S3]: {
name: 'S3',
description: t(`setting.${DataSourceKey.S3}Description`),
icon: <SvgIcon name={'data-source/s3'} width={38} />,
},
[DataSourceKey.NOTION]: {
name: 'Notion',
description: t(`setting.${DataSourceKey.NOTION}Description`),
icon: <SvgIcon name={'data-source/notion'} width={38} />,
},
[DataSourceKey.DISCORD]: {
name: 'Discord',
description: t(`setting.${DataSourceKey.DISCORD}Description`),
icon: <SvgIcon name={'data-source/discord'} width={38} />,
},
[DataSourceKey.CONFLUENCE]: {
name: 'Confluence',
description: t(`setting.${DataSourceKey.CONFLUENCE}Description`),
icon: <SvgIcon name={'data-source/confluence'} width={38} />,
},
[DataSourceKey.GOOGLE_DRIVE]: {
name: 'Google Drive',
description: t(`setting.${DataSourceKey.GOOGLE_DRIVE}Description`),
icon: <SvgIcon name={'data-source/google-drive'} width={38} />,
},
[DataSourceKey.GMAIL]: {
name: 'Gmail',
description: t(`setting.${DataSourceKey.GMAIL}Description`),
icon: <SvgIcon name={'data-source/gmail'} width={38} />,
},
[DataSourceKey.MOODLE]: {
name: 'Moodle',
description: t(`setting.${DataSourceKey.MOODLE}Description`),
icon: <SvgIcon name={'data-source/moodle'} width={38} />,
},
[DataSourceKey.JIRA]: {
name: 'Jira',
description: t(`setting.${DataSourceKey.JIRA}Description`),
icon: <SvgIcon name={'data-source/jira'} width={38} />,
},
[DataSourceKey.WEBDAV]: {
name: 'WebDAV',
description: t(`setting.${DataSourceKey.WEBDAV}Description`),
icon: <SvgIcon name={'data-source/webdav'} width={38} />,
},
[DataSourceKey.DROPBOX]: {
name: 'Dropbox',
description: t(`setting.${DataSourceKey.DROPBOX}Description`),
icon: <SvgIcon name={'data-source/dropbox'} width={38} />,
},
[DataSourceKey.BOX]: {
name: 'Box',
description: t(`setting.${DataSourceKey.BOX}Description`),
icon: <SvgIcon name={'data-source/box'} width={38} />,
},
};
};
export const useDataSourceInfo = () => {
const { t } = useTranslation();
const [dataSourceInfo, setDataSourceInfo] = useState<IDataSourceInfoMap>(
generateDataSourceInfo(t) as IDataSourceInfoMap,
);
useEffect(() => {
setDataSourceInfo(generateDataSourceInfo(t));
}, [t]);
return { dataSourceInfo };
};
export const DataSourceFormBaseFields = [

View File

@ -18,7 +18,7 @@ import {
DataSourceFormBaseFields,
DataSourceFormDefaultValues,
DataSourceFormFields,
DataSourceInfo,
useDataSourceInfo,
} from '../contant';
import {
useAddDataSource,
@ -32,10 +32,10 @@ const SourceDetailPage = () => {
const { data: detail } = useFetchDataSourceDetail();
const { handleResume } = useDataSourceResume();
const { dataSourceInfo } = useDataSourceInfo();
const detailInfo = useMemo(() => {
if (detail) {
return DataSourceInfo[detail.source];
return dataSourceInfo[detail.source];
}
}, [detail]);

View File

@ -12,10 +12,11 @@ import { useQuery, useQueryClient } from '@tanstack/react-query';
import { t } from 'i18next';
import { useCallback, useMemo, useState } from 'react';
import { useParams, useSearchParams } from 'umi';
import { DataSourceInfo, DataSourceKey } from './contant';
import { DataSourceKey, useDataSourceInfo } from './contant';
import { IDataSorceInfo, IDataSource, IDataSourceBase } from './interface';
export const useListDataSource = () => {
const { dataSourceInfo } = useDataSourceInfo();
const { data: list, isFetching } = useQuery<IDataSource[]>({
queryKey: ['data-source'],
queryFn: async () => {
@ -49,12 +50,12 @@ export const useListDataSource = () => {
[];
Object.keys(categorizedData).forEach((key: string) => {
const k = key as DataSourceKey;
if (DataSourceInfo[k]) {
if (dataSourceInfo[k]) {
sourceList.push({
id: k,
name: DataSourceInfo[k].name,
description: DataSourceInfo[k].description,
icon: DataSourceInfo[k].icon,
name: dataSourceInfo[k].name,
description: dataSourceInfo[k].description,
icon: dataSourceInfo[k].icon,
list: categorizedData[k] || [],
});
}

View File

@ -10,21 +10,21 @@ import {
} from '../components/user-setting-header';
import AddDataSourceModal from './add-datasource-modal';
import { AddedSourceCard } from './component/added-source-card';
import { DataSourceInfo, DataSourceKey } from './contant';
import { DataSourceKey, useDataSourceInfo } from './contant';
import { useAddDataSource, useListDataSource } from './hooks';
import { IDataSorceInfo } from './interface';
const dataSourceTemplates = Object.values(DataSourceKey).map((id) => {
return {
id,
name: DataSourceInfo[id].name,
description: DataSourceInfo[id].description,
icon: DataSourceInfo[id].icon,
};
});
const DataSource = () => {
const { t } = useTranslation();
const { dataSourceInfo } = useDataSourceInfo();
const dataSourceTemplates = Object.values(DataSourceKey).map((id) => {
return {
id,
name: dataSourceInfo[id].name,
description: dataSourceInfo[id].description,
icon: dataSourceInfo[id].icon,
};
});
// useListTenantUser();
const { categorizedList } = useListDataSource();

View File

@ -43,3 +43,11 @@ export interface IDataSourceLog {
tenant_id: string;
timeout_secs: number;
}
interface IDataSourceInfoItem {
name: string;
description: string;
icon: JSX.Element;
}
export type IDataSourceInfoMap = Record<DataSourceKey, IDataSourceInfoItem>;

View File

@ -11,12 +11,13 @@ import {
} from '@/hooks/use-user-setting-request';
import { cn } from '@/lib/utils';
import { Routes } from '@/routes';
import { t } from 'i18next';
import { TFunction } from 'i18next';
import { Banknote, Box, Server, Unplug, User, Users } from 'lucide-react';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useHandleMenuClick } from './hooks';
const menuItems = [
const menuItems = (t: TFunction) => [
{ icon: Server, label: t('setting.dataSources'), key: Routes.DataSource },
{ icon: Box, label: t('setting.model'), key: Routes.Model },
{ icon: Banknote, label: 'MCP', key: Routes.Mcp },
@ -32,12 +33,12 @@ const menuItems = [
// { icon: Cog, label: t('setting.system'), key: Routes.System },
// { icon: Banknote, label: 'Plan', key: Routes.Plan },
];
export function SideBar() {
const pathName = useSecondPathName();
const { data: userInfo } = useFetchUserInfo();
const { handleMenuClick, active } = useHandleMenuClick();
const { version, fetchSystemVersion } = useFetchSystemVersion();
const { t } = useTranslation();
useEffect(() => {
if (location.host !== Domain) {
fetchSystemVersion();
@ -56,7 +57,7 @@ export function SideBar() {
<p className="text-sm text-text-primary">{userInfo?.email}</p>
</div>
<div className="flex-1 overflow-auto">
{menuItems.map((item, idx) => {
{menuItems(t).map((item, idx) => {
const hoverKey = pathName === item.key;
return (
<div key={idx}>