mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Fix: Improve some functional issues with the data source. #10703 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -49,7 +49,7 @@ export interface IFileLogItem {
|
||||
process_duration: number;
|
||||
progress: number;
|
||||
progress_msg: string;
|
||||
source_from: string;
|
||||
source_type: string;
|
||||
status: string;
|
||||
task_type: string;
|
||||
tenant_id: string;
|
||||
|
||||
@ -11,11 +11,18 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { RunningStatusMap } from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
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 { formatDate, formatSecondsToHumanReadable } from '@/utils/date';
|
||||
import {
|
||||
ColumnDef,
|
||||
@ -77,25 +84,34 @@ export const getFileLogsTableColumns = (
|
||||
{
|
||||
accessorKey: 'fileName',
|
||||
header: t('fileName'),
|
||||
meta: { cellClassName: 'max-w-[20vw]' },
|
||||
cell: ({ row }) => (
|
||||
<div
|
||||
className="flex items-center gap-2 text-text-primary"
|
||||
// onClick={navigateToDataflowResult(
|
||||
// row.original.id,
|
||||
// row.original.kb_id,
|
||||
// )}
|
||||
>
|
||||
<FileIcon name={row.original.document_name}></FileIcon>
|
||||
{row.original.document_name}
|
||||
</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex gap-2 cursor-pointer">
|
||||
<FileIcon name={row.original.document_name}></FileIcon>
|
||||
<span className={cn('truncate')}>
|
||||
{row.original.document_name}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{row.original.document_name}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'source_from',
|
||||
header: t('source'),
|
||||
meta: { cellClassName: 'max-w-[10vw]' },
|
||||
cell: ({ row }) => (
|
||||
<div className="text-text-primary">
|
||||
{row.original.source_from || t('localUpload')}
|
||||
{row.original.source_type
|
||||
? DataSourceInfo[
|
||||
row.original.source_type as keyof typeof DataSourceInfo
|
||||
].icon
|
||||
: t('localUpload')}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
@ -66,7 +66,7 @@ export const AddedSourceCard = (props: IAddedSourceCardProps) => {
|
||||
<div
|
||||
key={item.id}
|
||||
className={cn(
|
||||
'flex flex-row items-center justify-between rounded-md bg-bg-input px-2 py-1 cursor-pointer',
|
||||
'flex flex-row items-center justify-between rounded-md bg-bg-card px-2 py-1 cursor-pointer',
|
||||
// { hidden: item.name.indexOf(filterString) <= -1 },
|
||||
)}
|
||||
onClick={() => {
|
||||
|
||||
@ -2,6 +2,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
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 { IDataSourceBase } from '@/pages/user-setting/data-source/interface';
|
||||
import { Link, Settings, Unlink } from 'lucide-react';
|
||||
@ -26,7 +27,7 @@ interface DataSourceItemProps extends IDataSourceNodeProps {
|
||||
|
||||
const DataSourceItem = (props: DataSourceItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { id, name, icon, openLinkModalFunc, unbindFunc } = props;
|
||||
const { id, name, icon, unbindFunc } = props;
|
||||
|
||||
const { navigateToDataSourceDetail } = useNavigatePage();
|
||||
const toDetail = (id: string) => {
|
||||
@ -71,7 +72,7 @@ const DataSourceItem = (props: DataSourceItemProps) => {
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-1 px-2 rounded-md border ">
|
||||
<div className="flex items-center gap-1">
|
||||
{icon}
|
||||
<div className="w-6 h-6 flex-shrink-0">{icon}</div>
|
||||
<div>{name}</div>
|
||||
</div>
|
||||
<div className="flex gap-1 items-center">
|
||||
@ -94,7 +95,12 @@ const DataSourceItem = (props: DataSourceItemProps) => {
|
||||
variant={'transparent'}
|
||||
className="border-none"
|
||||
onClick={() => {
|
||||
openUnlinkModal();
|
||||
// openUnlinkModal();
|
||||
delSourceModal({
|
||||
data: props,
|
||||
type: 'unlink',
|
||||
onOk: (data) => unbindFunc?.(data as DataSourceItemProps),
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Unlink />
|
||||
|
||||
@ -61,6 +61,7 @@ export const useFetchKnowledgeConfigurationOnMount = (
|
||||
'parser_id',
|
||||
'language',
|
||||
'parser_config',
|
||||
'connectors',
|
||||
'pagerank',
|
||||
'avatar',
|
||||
]),
|
||||
|
||||
@ -248,7 +248,7 @@ export default function DatasetSettings() {
|
||||
/>
|
||||
)}
|
||||
|
||||
<Divider />
|
||||
{/* <Divider /> */}
|
||||
{parseType === 1 && <ChunkMethodForm />}
|
||||
|
||||
{/* <LinkDataPipeline
|
||||
|
||||
@ -11,6 +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 { formatDate } from '@/utils/date';
|
||||
import { ColumnDef } from '@tanstack/table-core';
|
||||
import { ArrowUpDown } from 'lucide-react';
|
||||
@ -120,6 +121,19 @@ export function useDatasetTableColumns({
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'source_from',
|
||||
header: t('source'),
|
||||
cell: ({ row }) => (
|
||||
<div className="text-text-primary">
|
||||
{row.original.source_type
|
||||
? DataSourceInfo[
|
||||
row.original.source_type as keyof typeof DataSourceInfo
|
||||
]?.icon || t('localUpload')
|
||||
: t('localUpload')}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: t('enabled'),
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { DynamicForm, FormFieldConfig } from '@/components/dynamic-form';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
import { IModalProps } from '@/interfaces/common';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FieldValues } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { DynamicForm, FormFieldConfig } from './component/dynamic-form';
|
||||
import {
|
||||
DataSourceFormBaseFields,
|
||||
DataSourceFormDefaultValues,
|
||||
@ -39,7 +39,12 @@ const AddDataSourceModal = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t('setting.add')}
|
||||
title={
|
||||
<div className="flex flex-col">
|
||||
{sourceData?.icon}
|
||||
{t('setting.addDataSourceModalTital', { name: sourceData?.name })}
|
||||
</div>
|
||||
}
|
||||
open={visible || false}
|
||||
onOpenChange={(open) => !open && hideModal?.()}
|
||||
// onOk={() => handleOk()}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { Settings, Trash2 } from 'lucide-react';
|
||||
import { useDeleteDataSource } from '../hooks';
|
||||
import { IDataSorceInfo, IDataSourceBase } from '../interface';
|
||||
import { delSourceModal } from './delete-source-modal';
|
||||
|
||||
export type IAddedSourceCardProps = IDataSorceInfo & {
|
||||
list: IDataSourceBase[];
|
||||
@ -19,7 +19,7 @@ export const AddedSourceCard = (props: IAddedSourceCardProps) => {
|
||||
<Card className="bg-transparent border border-border-button px-5 pt-[10px] pb-5 rounded-md">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 p-0 pb-3">
|
||||
{/* <Users className="mr-2 h-5 w-5 text-[#1677ff]" /> */}
|
||||
<CardTitle className="text-base flex gap-1 font-normal">
|
||||
<CardTitle className="text-base items-center flex gap-1 font-normal">
|
||||
{icon}
|
||||
{name}
|
||||
</CardTitle>
|
||||
@ -28,7 +28,7 @@ export const AddedSourceCard = (props: IAddedSourceCardProps) => {
|
||||
{list.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="flex flex-row items-center justify-between rounded-md bg-bg-input px-[10px] py-4"
|
||||
className="flex flex-row items-center justify-between rounded-md bg-bg-card px-[10px] py-4"
|
||||
>
|
||||
<div className="text-sm text-text-secondary ">{item.name}</div>
|
||||
<div className="text-sm text-text-secondary flex gap-2">
|
||||
@ -39,9 +39,20 @@ export const AddedSourceCard = (props: IAddedSourceCardProps) => {
|
||||
toDetail(item.id);
|
||||
}}
|
||||
/>
|
||||
<ConfirmDeleteDialog onOk={() => handleDelete(item)}>
|
||||
<Trash2 className="cursor-pointer" size={14} />
|
||||
</ConfirmDeleteDialog>
|
||||
{/* <ConfirmDeleteDialog onOk={() => handleDelete(item)}> */}
|
||||
<Trash2
|
||||
className="cursor-pointer"
|
||||
size={14}
|
||||
onClick={() =>
|
||||
delSourceModal({
|
||||
data: item,
|
||||
onOk: () => {
|
||||
handleDelete(item);
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
{/* </ConfirmDeleteDialog> */}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
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';
|
||||
|
||||
export type IDelSourceModalProps<T> = Partial<ModalType> & {
|
||||
data?: T;
|
||||
type?: 'delete' | 'unlink';
|
||||
onOk?: (data?: T) => void;
|
||||
};
|
||||
|
||||
export const delSourceModal = <T extends IDataSourceBase>(
|
||||
props: IDelSourceModalProps<T>,
|
||||
) => {
|
||||
const { data, onOk, type = 'delete', ...otherProps } = props;
|
||||
console.log('data', data);
|
||||
const config = {
|
||||
title:
|
||||
type === 'delete'
|
||||
? t('setting.deleteSourceModalTitle')
|
||||
: t('dataflowParser.unlinkSourceModalTitle'),
|
||||
content: (
|
||||
<div className="px-2 py-6">
|
||||
<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 : ''}
|
||||
</div>
|
||||
<div>{data?.name}</div>
|
||||
</div>
|
||||
{type === 'delete' ? (
|
||||
<div
|
||||
className="text-sm text-text-secondary"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('setting.deleteSourceModalContent'),
|
||||
}}
|
||||
></div>
|
||||
) : (
|
||||
<div
|
||||
className="text-sm text-text-secondary"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('dataflowParser.unlinkSourceModalContent'),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
confirmText:
|
||||
type === 'delete'
|
||||
? t('setting.deleteSourceModalConfirmText')
|
||||
: t('dataflowParser.unlinkSourceModalConfirmText'),
|
||||
};
|
||||
Modal.show({
|
||||
visible: true,
|
||||
className: '!w-[560px]',
|
||||
...otherProps,
|
||||
title: config.title,
|
||||
children: config.content,
|
||||
onVisibleChange: () => {
|
||||
Modal.hide();
|
||||
},
|
||||
footer: (
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant={'outline'} onClick={() => Modal.hide()}>
|
||||
{t('dataflowParser.changeStepModalCancelText')}
|
||||
</Button>
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
className="!bg-state-error text-text-base"
|
||||
onClick={() => {
|
||||
onOk?.(data);
|
||||
Modal.hide();
|
||||
}}
|
||||
>
|
||||
{config.confirmText}
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
};
|
||||
@ -1,12 +1,12 @@
|
||||
import { FormFieldType } from '@/components/dynamic-form';
|
||||
import SvgIcon from '@/components/svg-icon';
|
||||
import { t } from 'i18next';
|
||||
import { FormFieldType } from './component/dynamic-form';
|
||||
|
||||
export enum DataSourceKey {
|
||||
CONFLUENCE = 'confluence',
|
||||
S3 = 's3',
|
||||
NOTION = 'notion',
|
||||
DISCORD = 'discord',
|
||||
// CONFLUENNCE = 'confluence',
|
||||
// GMAIL = 'gmail',
|
||||
// GOOGLE_DRIVER = 'google_driver',
|
||||
// JIRA = 'jira',
|
||||
@ -19,17 +19,22 @@ export const DataSourceInfo = {
|
||||
[DataSourceKey.S3]: {
|
||||
name: 'S3',
|
||||
description: t(`setting.${DataSourceKey.S3}Description`),
|
||||
icon: <SvgIcon name={'data-source/s3'} width={28} />,
|
||||
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={28} />,
|
||||
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={28} />,
|
||||
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} />,
|
||||
},
|
||||
};
|
||||
|
||||
@ -71,7 +76,7 @@ export const DataSourceFormFields = {
|
||||
{
|
||||
label: 'AWS Secret Access Key',
|
||||
name: 'config.credentials.aws_secret_access_key',
|
||||
type: FormFieldType.Text,
|
||||
type: FormFieldType.Password,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
@ -103,7 +108,7 @@ export const DataSourceFormFields = {
|
||||
{
|
||||
label: 'Notion Integration Token',
|
||||
name: 'config.credentials.notion_integration_token',
|
||||
type: FormFieldType.Text,
|
||||
type: FormFieldType.Password,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
@ -117,7 +122,7 @@ export const DataSourceFormFields = {
|
||||
{
|
||||
label: 'Discord Bot Token',
|
||||
name: 'config.credentials.discord_bot_token',
|
||||
type: FormFieldType.Text,
|
||||
type: FormFieldType.Password,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
@ -133,6 +138,38 @@ export const DataSourceFormFields = {
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
|
||||
[DataSourceKey.CONFLUENCE]: [
|
||||
{
|
||||
label: 'Confluence Username',
|
||||
name: 'config.credentials.confluence_username',
|
||||
type: FormFieldType.Text,
|
||||
required: true,
|
||||
tooltip: 'A descriptive name for the connector.',
|
||||
},
|
||||
{
|
||||
label: 'Confluence Access Token',
|
||||
name: 'config.credentials.confluence_access_token',
|
||||
type: FormFieldType.Password,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: 'Wiki Base URL',
|
||||
name: 'config.wiki_base',
|
||||
type: FormFieldType.Text,
|
||||
required: false,
|
||||
tooltip:
|
||||
'The base URL of your Confluence instance (e.g., https://your-domain.atlassian.net/wiki)',
|
||||
},
|
||||
{
|
||||
label: 'Is Cloud',
|
||||
name: 'config.is_cloud',
|
||||
type: FormFieldType.Checkbox,
|
||||
required: false,
|
||||
tooltip:
|
||||
'Check if this is a Confluence Cloud instance, uncheck for Confluence Server/Data Center',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const DataSourceFormDefaultValues = {
|
||||
@ -170,4 +207,16 @@ export const DataSourceFormDefaultValues = {
|
||||
},
|
||||
},
|
||||
},
|
||||
[DataSourceKey.CONFLUENCE]: {
|
||||
name: '',
|
||||
source: DataSourceKey.CONFLUENCE,
|
||||
config: {
|
||||
wiki_base: '',
|
||||
is_cloud: true,
|
||||
credentials: {
|
||||
confluence_username: '',
|
||||
confluence_access_token: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import BackButton from '@/components/back-button';
|
||||
import {
|
||||
DynamicForm,
|
||||
DynamicFormRef,
|
||||
FormFieldConfig,
|
||||
FormFieldType,
|
||||
} from '@/components/dynamic-form';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
@ -8,12 +14,6 @@ import { debounce } from 'lodash';
|
||||
import { CirclePause, Repeat } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { FieldValues } from 'react-hook-form';
|
||||
import {
|
||||
DynamicForm,
|
||||
DynamicFormRef,
|
||||
FormFieldConfig,
|
||||
FormFieldType,
|
||||
} from '../component/dynamic-form';
|
||||
import {
|
||||
DataSourceFormBaseFields,
|
||||
DataSourceFormDefaultValues,
|
||||
@ -112,7 +112,7 @@ const SourceDetailPage = () => {
|
||||
<div className="flex items-center gap-1 w-full relative">
|
||||
<Input {...fieldProps} type={FormFieldType.Number} />
|
||||
<span className="absolute right-0 -translate-x-3 text-text-secondary italic ">
|
||||
minutes
|
||||
seconds
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
|
||||
@ -145,7 +145,7 @@ export const DataSourceLogsTable = () => {
|
||||
const handleToDataSetDetail = useCallback(
|
||||
(id: string) => {
|
||||
console.log('handleToDataSetDetail', id);
|
||||
navigate(`${Routes.DatasetBase}${Routes.DataSetSetting}/${id}`);
|
||||
navigate(`${Routes.DatasetBase}${Routes.DatasetBase}/${id}`);
|
||||
},
|
||||
[navigate],
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { CardTitle } from '@/components/ui/card';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Spotlight from '@/components/spotlight';
|
||||
@ -11,21 +11,17 @@ import { DataSourceInfo, DataSourceKey } from './contant';
|
||||
import { useAddDataSource, useListDataSource } from './hooks';
|
||||
import { IDataSorceInfo } from './interface';
|
||||
const dataSourceTemplates = [
|
||||
{
|
||||
id: DataSourceKey.CONFLUENCE,
|
||||
name: DataSourceInfo[DataSourceKey.CONFLUENCE].name,
|
||||
description: DataSourceInfo[DataSourceKey.CONFLUENCE].description,
|
||||
icon: DataSourceInfo[DataSourceKey.CONFLUENCE].icon,
|
||||
},
|
||||
{
|
||||
id: DataSourceKey.S3,
|
||||
name: DataSourceInfo[DataSourceKey.S3].name,
|
||||
description: DataSourceInfo[DataSourceKey.S3].description,
|
||||
icon: DataSourceInfo[DataSourceKey.S3].icon,
|
||||
list: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'S3 Bucket 1',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'S3 Bucket 1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: DataSourceKey.DISCORD,
|
||||
@ -94,16 +90,16 @@ const DataSource = () => {
|
||||
<div className="w-full flex flex-col gap-4 relative ">
|
||||
<Spotlight />
|
||||
|
||||
<Card className="bg-transparent border-none px-0">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 px-4 pt-4 pb-0">
|
||||
<CardTitle className="text-2xl font-medium">
|
||||
{t('setting.dataSources')}
|
||||
<div className="text-sm text-text-secondary">
|
||||
{t('setting.datasourceDescription')}
|
||||
</div>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
{/* <Card className="bg-transparent border-none px-0"> */}
|
||||
<section className="flex flex-row items-center justify-between space-y-0 px-4 pt-4 pb-0">
|
||||
<div className="text-2xl font-medium">
|
||||
{t('setting.dataSources')}
|
||||
<div className="text-sm text-text-secondary">
|
||||
{t('setting.datasourceDescription')}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* </Card> */}
|
||||
<Separator className="border-border-button bg-border-button " />
|
||||
<div className=" flex flex-col gap-4 p-4 max-h-[calc(100vh-120px)] overflow-y-auto overflow-x-hidden scrollbar-auto">
|
||||
<div className="flex flex-col gap-3">
|
||||
@ -111,8 +107,8 @@ const DataSource = () => {
|
||||
<AddedSourceCard key={index} {...item} />
|
||||
))}
|
||||
</div>
|
||||
<Card className="bg-transparent border-none mt-8">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 p-0 pb-4">
|
||||
<section className="bg-transparent border-none mt-8">
|
||||
<header className="flex flex-row items-center justify-between space-y-0 p-0 pb-4">
|
||||
{/* <Users className="mr-2 h-5 w-5 text-[#1677ff]" /> */}
|
||||
<CardTitle className="text-2xl font-semibold">
|
||||
{t('setting.availableSources')}
|
||||
@ -120,16 +116,16 @@ const DataSource = () => {
|
||||
{t('setting.availableSourcesDescription')}
|
||||
</div>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
</header>
|
||||
<main className="p-0">
|
||||
{/* <TenantTable searchTerm={searchTerm}></TenantTable> */}
|
||||
<div className="grid sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-4 3xl:grid-cols-4 gap-4">
|
||||
{dataSourceTemplates.map((item, index) => (
|
||||
<AbailableSourceCard {...item} key={index} />
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{addingModalVisible && (
|
||||
|
||||
Reference in New Issue
Block a user