mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Theme switch support (#3568)
### What problem does this PR solve? - [x] New Feature (non-breaking change which adds functionality) --------- Co-authored-by: Yingfeng <yingfeng.zhang@gmail.com> Co-authored-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
@ -29,3 +29,6 @@
|
||||
.cardSelected {
|
||||
background-color: @selectedBackgroundColor;
|
||||
}
|
||||
.cardSelectedDark {
|
||||
background-color: #ffffff2f;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import classNames from 'classnames';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { ChunkTextMode } from '../../constant';
|
||||
import styles from './index.less';
|
||||
|
||||
@ -31,6 +32,7 @@ const ChunkCard = ({
|
||||
}: IProps) => {
|
||||
const available = Number(item.available_int);
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const { theme } = useTheme();
|
||||
|
||||
const onChange = (checked: boolean) => {
|
||||
setEnabled(checked);
|
||||
@ -56,7 +58,8 @@ const ChunkCard = ({
|
||||
return (
|
||||
<Card
|
||||
className={classNames(styles.chunkCard, {
|
||||
[styles.cardSelected]: selected,
|
||||
[`${theme === 'dark' ? styles.cardSelectedDark : styles.cardSelected}`]:
|
||||
selected,
|
||||
})}
|
||||
>
|
||||
<Flex gap={'middle'} justify={'space-between'}>
|
||||
|
||||
@ -37,16 +37,14 @@ const CategoryPanel = ({ chunkMethod }: { chunkMethod: string }) => {
|
||||
{imageList.length > 0 ? (
|
||||
<>
|
||||
<Title level={5} className={styles.topTitle}>
|
||||
"{item.title}" {t('methodTitle')}
|
||||
{`"${item.title}" ${t('methodTitle')}`}
|
||||
</Title>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: DOMPurify.sanitize(item.description),
|
||||
}}
|
||||
></p>
|
||||
<Title level={5}>
|
||||
"{item.title}" {t('methodExamples')}
|
||||
</Title>
|
||||
<Title level={5}>{`"${item.title}" ${t('methodExamples')}`}</Title>
|
||||
<Text>{t('methodExamplesDescription')}</Text>
|
||||
<Row gutter={[10, 10]} className={styles.imageRow}>
|
||||
{imageList.map((x) => (
|
||||
|
||||
@ -70,6 +70,7 @@ const ConfigurationForm = ({ form }: { form: FormInstance }) => {
|
||||
<Select placeholder={t('languagePlaceholder')}>
|
||||
<Option value="English">{t('english')}</Option>
|
||||
<Option value="Chinese">{t('chinese')}</Option>
|
||||
<Option value="Vietnamese">{t('vietnamese')}</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: @fontWeight700;
|
||||
color: @gray2;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.knowledgeDescription {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
.testingWrapper {
|
||||
flex: 1;
|
||||
background-color: @grayBackground;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
.testingControlWrapper {
|
||||
width: 350px;
|
||||
background-color: white;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
padding: 30px 20px;
|
||||
overflow: auto;
|
||||
height: calc(100vh - 160px);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
.testingResultWrapper {
|
||||
flex: 1;
|
||||
background-color: white;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
padding: 30px 20px;
|
||||
overflow: auto;
|
||||
height: calc(100vh - 160px);
|
||||
@ -24,7 +24,7 @@
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(244, 235, 255, 1);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ const TestingResult = ({ handleTesting }: IProps) => {
|
||||
>
|
||||
<Space>
|
||||
<span>
|
||||
{selectedDocumentIds?.length ?? 0}/{documents.length}
|
||||
{selectedDocumentIds?.length ?? 0}/{documents?.length ?? 0}
|
||||
</span>
|
||||
{t('filesSelected')}
|
||||
</Space>
|
||||
@ -105,7 +105,7 @@ const TestingResult = ({ handleTesting }: IProps) => {
|
||||
flex={1}
|
||||
className={styles.selectFilesCollapse}
|
||||
>
|
||||
{chunks.map((x) => (
|
||||
{chunks?.map((x) => (
|
||||
<Card key={x.chunk_id} title={<ChunkTitle item={x}></ChunkTitle>}>
|
||||
<Flex gap={'middle'}>
|
||||
{x.img_id && (
|
||||
|
||||
@ -6,13 +6,13 @@
|
||||
flex: 1;
|
||||
overflow-x: auto;
|
||||
height: 100%;
|
||||
background-color: rgba(247, 248, 250, 1);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
padding: 16px 20px 28px 40px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.content {
|
||||
background-color: white;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
margin-top: 16px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@ -42,224 +42,6 @@ const ModelSetting = ({
|
||||
})}
|
||||
>
|
||||
{visible && <LlmSettingItems prefix="llm_setting"></LlmSettingItems>}
|
||||
{/* <Form.Item
|
||||
label={t('model')}
|
||||
name="llm_id"
|
||||
tooltip={t('modelTip')}
|
||||
rules={[{ required: true, message: t('modelMessage') }]}
|
||||
>
|
||||
<Select options={modelOptions[LlmModelType.Chat]} showSearch />
|
||||
</Form.Item>
|
||||
<Divider></Divider>
|
||||
<Form.Item
|
||||
label={t('freedom')}
|
||||
name="parameters"
|
||||
tooltip={t('freedomTip')}
|
||||
initialValue={ModelVariableType.Precise}
|
||||
>
|
||||
<Select<ModelVariableType>
|
||||
options={parameterOptions}
|
||||
onChange={handleParametersChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('temperature')} tooltip={t('temperatureTip')}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item
|
||||
name={'temperatureEnabled'}
|
||||
valuePropName="checked"
|
||||
noStyle
|
||||
>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['temperatureEnabled']}>
|
||||
{({ getFieldValue }) => {
|
||||
const disabled = !getFieldValue('temperatureEnabled');
|
||||
return (
|
||||
<>
|
||||
<Flex flex={1}>
|
||||
<Form.Item name={['llm_setting', 'temperature']} noStyle>
|
||||
<Slider
|
||||
className={styles.variableSlider}
|
||||
max={1}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item name={['llm_setting', 'temperature']} noStyle>
|
||||
<InputNumber
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('topP')} tooltip={t('topPTip')}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item name={'topPEnabled'} valuePropName="checked" noStyle>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['topPEnabled']}>
|
||||
{({ getFieldValue }) => {
|
||||
const disabled = !getFieldValue('topPEnabled');
|
||||
return (
|
||||
<>
|
||||
<Flex flex={1}>
|
||||
<Form.Item name={['llm_setting', 'top_p']} noStyle>
|
||||
<Slider
|
||||
className={styles.variableSlider}
|
||||
max={1}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item name={['llm_setting', 'top_p']} noStyle>
|
||||
<InputNumber
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('presencePenalty')} tooltip={t('presencePenaltyTip')}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item
|
||||
name={'presencePenaltyEnabled'}
|
||||
valuePropName="checked"
|
||||
noStyle
|
||||
>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['presencePenaltyEnabled']}>
|
||||
{({ getFieldValue }) => {
|
||||
const disabled = !getFieldValue('presencePenaltyEnabled');
|
||||
return (
|
||||
<>
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['llm_setting', 'presence_penalty']}
|
||||
noStyle
|
||||
>
|
||||
<Slider
|
||||
className={styles.variableSlider}
|
||||
max={1}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item name={['llm_setting', 'presence_penalty']} noStyle>
|
||||
<InputNumber
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('frequencyPenalty')}
|
||||
tooltip={t('frequencyPenaltyTip')}
|
||||
>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item
|
||||
name={'frequencyPenaltyEnabled'}
|
||||
valuePropName="checked"
|
||||
noStyle
|
||||
>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['frequencyPenaltyEnabled']}>
|
||||
{({ getFieldValue }) => {
|
||||
const disabled = !getFieldValue('frequencyPenaltyEnabled');
|
||||
return (
|
||||
<>
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['llm_setting', 'frequency_penalty']}
|
||||
noStyle
|
||||
>
|
||||
<Slider
|
||||
className={styles.variableSlider}
|
||||
max={1}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item
|
||||
name={['llm_setting', 'frequency_penalty']}
|
||||
noStyle
|
||||
>
|
||||
<InputNumber
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('maxTokens')} tooltip={t('maxTokensTip')}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item name={'maxTokensEnabled'} valuePropName="checked" noStyle>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['maxTokensEnabled']}>
|
||||
{({ getFieldValue }) => {
|
||||
const disabled = !getFieldValue('maxTokensEnabled');
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex flex={1}>
|
||||
<Form.Item name={['llm_setting', 'max_tokens']} noStyle>
|
||||
<Slider
|
||||
className={styles.variableSlider}
|
||||
max={2048}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item name={['llm_setting', 'max_tokens']} noStyle>
|
||||
<InputNumber
|
||||
disabled={disabled}
|
||||
className={styles.sliderInputNumber}
|
||||
max={2048}
|
||||
min={0}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item> */}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
@ -27,6 +27,12 @@
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
.chatAppCardSelectedDark {
|
||||
:global(.ant-card-body) {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatTitleWrapper {
|
||||
width: 220px;
|
||||
@ -62,6 +68,12 @@
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
.chatTitleCardSelectedDark {
|
||||
:global(.ant-card-body) {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 0;
|
||||
|
||||
@ -30,6 +30,7 @@ import {
|
||||
} from './hooks';
|
||||
|
||||
import SvgIcon from '@/components/svg-icon';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import {
|
||||
useClickConversationCard,
|
||||
useClickDialogCard,
|
||||
@ -51,6 +52,7 @@ const Chat = () => {
|
||||
const { handleClickDialog } = useClickDialogCard();
|
||||
const { handleClickConversation } = useClickConversationCard();
|
||||
const { dialogId, conversationId } = useGetChatSearchParams();
|
||||
const { theme } = useTheme();
|
||||
const {
|
||||
list: conversationList,
|
||||
addTemporaryConversation,
|
||||
@ -243,7 +245,9 @@ const Chat = () => {
|
||||
key={x.id}
|
||||
hoverable
|
||||
className={classNames(styles.chatAppCard, {
|
||||
[styles.chatAppCardSelected]: dialogId === x.id,
|
||||
[theme === 'dark'
|
||||
? styles.chatAppCardSelectedDark
|
||||
: styles.chatAppCardSelected]: dialogId === x.id,
|
||||
})}
|
||||
onMouseEnter={handleAppCardEnter(x.id)}
|
||||
onMouseLeave={handleItemLeave}
|
||||
@ -316,7 +320,9 @@ const Chat = () => {
|
||||
onMouseEnter={handleConversationCardEnter(x.id)}
|
||||
onMouseLeave={handleConversationItemLeave}
|
||||
className={classNames(styles.chatTitleCard, {
|
||||
[styles.chatTitleCardSelected]: x.id === conversationId,
|
||||
[theme === 'dark'
|
||||
? styles.chatTitleCardSelectedDark
|
||||
: styles.chatTitleCardSelected]: x.id === conversationId,
|
||||
})}
|
||||
>
|
||||
<Flex justify="space-between" align="center">
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
:global(.document-container) {
|
||||
padding: 30px;
|
||||
width: 700px;
|
||||
background: white;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.contextMenu {
|
||||
background: white;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-style: solid;
|
||||
box-shadow: 10px 19px 20px rgba(0, 0, 0, 10%);
|
||||
position: absolute;
|
||||
@ -13,6 +13,6 @@
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: white;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,3 +13,19 @@
|
||||
.edgeButton:hover {
|
||||
box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.edgeButtonDark {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: #0e0c0c;
|
||||
border: 1px solid #fff;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.edgeButtonDark:hover {
|
||||
box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
} from 'reactflow';
|
||||
import useGraphStore from '../../store';
|
||||
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { useFetchFlow } from '@/hooks/flow-hooks';
|
||||
import { useMemo } from 'react';
|
||||
import styles from './index.less';
|
||||
@ -33,7 +34,7 @@ export function ButtonEdge({
|
||||
targetY,
|
||||
targetPosition,
|
||||
});
|
||||
|
||||
const { theme } = useTheme();
|
||||
const selectedStyle = useMemo(() => {
|
||||
return selected ? { strokeWidth: 2, stroke: '#1677ff' } : {};
|
||||
}, [selected]);
|
||||
@ -93,7 +94,9 @@ export function ButtonEdge({
|
||||
className="nodrag nopan"
|
||||
>
|
||||
<button
|
||||
className={styles.edgeButton}
|
||||
className={
|
||||
theme === 'dark' ? styles.edgeButtonDark : styles.edgeButton
|
||||
}
|
||||
type="button"
|
||||
onClick={onEdgeClick}
|
||||
>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import get from 'lodash/get';
|
||||
@ -18,12 +19,16 @@ import styles from './index.less';
|
||||
export function BeginNode({ selected, data }: NodeProps<NodeData>) {
|
||||
const { t } = useTranslation();
|
||||
const query: BeginQuery[] = get(data, 'form.query', []);
|
||||
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.ragNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.ragNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
type="source"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import LLMLabel from '@/components/llm-select/llm-label';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
@ -11,12 +12,16 @@ import NodeHeader from './node-header';
|
||||
|
||||
export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
|
||||
const { positions } = useBuildCategorizeHandlePositions({ data, id });
|
||||
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
type="target"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import LLMLabel from '@/components/llm-select/llm-label';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
@ -17,12 +18,16 @@ export function GenerateNode({
|
||||
}: NodeProps<NodeData>) {
|
||||
const parameters: IGenerateParameter[] = get(data, 'form.parameters', []);
|
||||
const getLabel = useGetComponentLabelByValue(id);
|
||||
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -10,9 +10,11 @@
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.dark {
|
||||
background: rgb(63, 63, 63) !important;
|
||||
}
|
||||
.ragNode {
|
||||
.commonNode();
|
||||
|
||||
.nodeName {
|
||||
font-size: 10px;
|
||||
color: black;
|
||||
@ -95,7 +97,7 @@
|
||||
min-width: 140px;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
padding: 8px;
|
||||
border-radius: 10px;
|
||||
min-height: 128px;
|
||||
.noteTitle {
|
||||
@ -105,6 +107,13 @@
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.noteTitleDark {
|
||||
background-color: #edfcff;
|
||||
font-size: 12px;
|
||||
padding: 6px 6px 4px;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.noteForm {
|
||||
margin-top: 4px;
|
||||
height: calc(100% - 50px);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import classNames from 'classnames';
|
||||
import { Handle, NodeProps, Position } from 'reactflow';
|
||||
import { NodeData } from '../../interface';
|
||||
@ -11,11 +12,16 @@ export function RagNode({
|
||||
isConnectable = true,
|
||||
selected,
|
||||
}: NodeProps<NodeData>) {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.ragNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.ragNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
@ -15,12 +16,17 @@ export function InvokeNode({
|
||||
selected,
|
||||
}: NodeProps<NodeData>) {
|
||||
const { t } = useTranslation();
|
||||
const { theme } = useTheme();
|
||||
const url = get(data, 'form.url');
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.ragNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.ragNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import LLMLabel from '@/components/llm-select/llm-label';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
import { Handle, NodeProps, Position } from 'reactflow';
|
||||
@ -13,11 +14,16 @@ export function KeywordNode({
|
||||
isConnectable = true,
|
||||
selected,
|
||||
}: NodeProps<NodeData>) {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import classNames from 'classnames';
|
||||
import { Handle, NodeProps, Position } from 'reactflow';
|
||||
import { NodeData } from '../../interface';
|
||||
@ -11,11 +12,16 @@ export function LogicNode({
|
||||
isConnectable = true,
|
||||
selected,
|
||||
}: NodeProps<NodeData>) {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
@ -14,12 +15,16 @@ export function MessageNode({
|
||||
selected,
|
||||
}: NodeProps<NodeData>) {
|
||||
const messages: string[] = get(data, 'form.messages', []);
|
||||
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -5,6 +5,7 @@ import { NodeData } from '../../interface';
|
||||
import NodeDropdown from './dropdown';
|
||||
|
||||
import SvgIcon from '@/components/svg-icon';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { memo, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@ -23,6 +24,7 @@ const controlStyle = {
|
||||
function NoteNode({ data, id }: NodeProps<NodeData>) {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const { theme } = useTheme();
|
||||
|
||||
const { name, handleNameBlur, handleNameChange } = useHandleNodeNameChange({
|
||||
id,
|
||||
@ -48,10 +50,15 @@ function NoteNode({ data, id }: NodeProps<NodeData>) {
|
||||
}}
|
||||
></SvgIcon>
|
||||
</NodeResizeControl>
|
||||
<section className={styles.noteNode}>
|
||||
<section
|
||||
className={classNames(
|
||||
styles.noteNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
)}
|
||||
>
|
||||
<Flex
|
||||
justify={'space-between'}
|
||||
className={classNames(styles.noteTitle, 'note-drag-handle')}
|
||||
className={classNames('note-drag-handle')}
|
||||
align="center"
|
||||
gap={6}
|
||||
>
|
||||
|
||||
@ -5,6 +5,7 @@ import JsonView from 'react18-json-view';
|
||||
import 'react18-json-view/src/style.css';
|
||||
import { useGetComponentLabelByValue, useReplaceIdWithText } from '../../hooks';
|
||||
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
@ -29,6 +30,7 @@ export function NextNodePopover({ children, nodeId, name }: IProps) {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const { data } = useFetchFlow();
|
||||
const { theme } = useTheme();
|
||||
const component = useMemo(() => {
|
||||
return get(data, ['dsl', 'components', nodeId], {});
|
||||
}, [nodeId, data]);
|
||||
@ -64,7 +66,16 @@ export function NextNodePopover({ children, nodeId, name }: IProps) {
|
||||
<div className="flex w-full gap-4 flex-col">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<span className="font-semibold text-[14px]">{t('input')}</span>
|
||||
<div className="bg-gray-100 p-1 rounded">
|
||||
<div
|
||||
style={
|
||||
theme === 'dark'
|
||||
? {
|
||||
backgroundColor: 'rgba(150, 150, 150, 0.2)',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
className={`bg-gray-100 p-1 rounded`}
|
||||
>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
@ -85,7 +96,16 @@ export function NextNodePopover({ children, nodeId, name }: IProps) {
|
||||
</div>
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<span className="font-semibold text-[14px]">{t('output')}</span>
|
||||
<div className="bg-gray-100 p-1 rounded">
|
||||
<div
|
||||
style={
|
||||
theme === 'dark'
|
||||
? {
|
||||
backgroundColor: 'rgba(150, 150, 150, 0.2)',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
className="bg-gray-100 p-1 rounded"
|
||||
>
|
||||
<JsonView
|
||||
src={replacedOutput}
|
||||
displaySize={30}
|
||||
|
||||
@ -4,6 +4,7 @@ import { Handle, NodeProps, Position } from 'reactflow';
|
||||
import { NodeData } from '../../interface';
|
||||
import { RightHandleStyle } from './handle-icon';
|
||||
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { get } from 'lodash';
|
||||
import { useReplaceIdWithName } from '../../hooks';
|
||||
import styles from './index.less';
|
||||
@ -13,12 +14,16 @@ export function RelevantNode({ id, data, selected }: NodeProps<NodeData>) {
|
||||
const yes = get(data, 'form.yes');
|
||||
const no = get(data, 'form.no');
|
||||
const replaceIdWithName = useReplaceIdWithName();
|
||||
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
type="target"
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Flex } from 'antd';
|
||||
@ -17,6 +18,7 @@ export function RetrievalNode({
|
||||
selected,
|
||||
}: NodeProps<NodeData>) {
|
||||
const knowledgeBaseIds: string[] = get(data, 'form.kb_ids', []);
|
||||
const { theme } = useTheme();
|
||||
const { list: knowledgeList } = useFetchKnowledgeList(true);
|
||||
const knowledgeBases = useMemo(() => {
|
||||
return knowledgeBaseIds.map((x) => {
|
||||
@ -31,9 +33,13 @@ export function RetrievalNode({
|
||||
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import LLMLabel from '@/components/llm-select/llm-label';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
import { Handle, NodeProps, Position } from 'reactflow';
|
||||
@ -13,11 +14,16 @@ export function RewriteNode({
|
||||
isConnectable = true,
|
||||
selected,
|
||||
}: NodeProps<NodeData>) {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { Divider, Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { Handle, NodeProps, Position } from 'reactflow';
|
||||
@ -55,12 +56,16 @@ const ConditionBlock = ({
|
||||
|
||||
export function SwitchNode({ id, data, selected }: NodeProps<NodeData>) {
|
||||
const { positions } = useBuildSwitchHandlePositions({ data, id });
|
||||
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
type="target"
|
||||
|
||||
@ -7,6 +7,7 @@ import { IGenerateParameter, NodeData } from '../../interface';
|
||||
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
||||
import NodeHeader from './node-header';
|
||||
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import styles from './index.less';
|
||||
|
||||
export function TemplateNode({
|
||||
@ -17,12 +18,17 @@ export function TemplateNode({
|
||||
}: NodeProps<NodeData>) {
|
||||
const parameters: IGenerateParameter[] = get(data, 'form.parameters', []);
|
||||
const getLabel = useGetComponentLabelByValue(id);
|
||||
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
className={classNames(styles.logicNode, {
|
||||
[styles.selectedNode]: selected,
|
||||
})}
|
||||
className={classNames(
|
||||
styles.logicNode,
|
||||
theme === 'dark' ? styles.dark : '',
|
||||
|
||||
{
|
||||
[styles.selectedNode]: selected,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Handle
|
||||
id="c"
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
import {
|
||||
GitHubIcon,
|
||||
KeywordIcon,
|
||||
QWeatherIcon,
|
||||
WikipediaIcon,
|
||||
} from '@/assets/icon/Icon';
|
||||
import { ReactComponent as AkShareIcon } from '@/assets/svg/akshare.svg';
|
||||
import { ReactComponent as ArXivIcon } from '@/assets/svg/arxiv.svg';
|
||||
import { ReactComponent as baiduFanyiIcon } from '@/assets/svg/baidu-fanyi.svg';
|
||||
@ -10,20 +16,16 @@ import { ReactComponent as DeepLIcon } from '@/assets/svg/deepl.svg';
|
||||
import { ReactComponent as DuckIcon } from '@/assets/svg/duck.svg';
|
||||
import { ReactComponent as EmailIcon } from '@/assets/svg/email.svg';
|
||||
import { ReactComponent as ExeSqlIcon } from '@/assets/svg/exesql.svg';
|
||||
import { ReactComponent as GithubIcon } from '@/assets/svg/github.svg';
|
||||
import { ReactComponent as GoogleScholarIcon } from '@/assets/svg/google-scholar.svg';
|
||||
import { ReactComponent as GoogleIcon } from '@/assets/svg/google.svg';
|
||||
import { ReactComponent as InvokeIcon } from '@/assets/svg/invoke-ai.svg';
|
||||
import { ReactComponent as Jin10Icon } from '@/assets/svg/jin10.svg';
|
||||
import { ReactComponent as KeywordIcon } from '@/assets/svg/keyword.svg';
|
||||
import { ReactComponent as NoteIcon } from '@/assets/svg/note.svg';
|
||||
import { ReactComponent as PubMedIcon } from '@/assets/svg/pubmed.svg';
|
||||
import { ReactComponent as QWeatherIcon } from '@/assets/svg/qweather.svg';
|
||||
import { ReactComponent as SwitchIcon } from '@/assets/svg/switch.svg';
|
||||
import { ReactComponent as TemplateIcon } from '@/assets/svg/template.svg';
|
||||
import { ReactComponent as TuShareIcon } from '@/assets/svg/tushare.svg';
|
||||
import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg';
|
||||
import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg';
|
||||
import { ReactComponent as YahooFinanceIcon } from '@/assets/svg/yahoo-finance.svg';
|
||||
|
||||
// 邮件功能
|
||||
@ -116,7 +118,7 @@ export const operatorIconMap = {
|
||||
[Operator.Bing]: BingIcon,
|
||||
[Operator.GoogleScholar]: GoogleScholarIcon,
|
||||
[Operator.DeepL]: DeepLIcon,
|
||||
[Operator.GitHub]: GithubIcon,
|
||||
[Operator.GitHub]: GitHubIcon,
|
||||
[Operator.BaiduFanyi]: baiduFanyiIcon,
|
||||
[Operator.QWeather]: QWeatherIcon,
|
||||
[Operator.ExeSQL]: ExeSqlIcon,
|
||||
@ -193,11 +195,10 @@ export const operatorMap: Record<
|
||||
[Operator.KeywordExtract]: {
|
||||
width: 70,
|
||||
height: 70,
|
||||
backgroundColor: '#0f0e0f',
|
||||
color: '#0f0e0f',
|
||||
backgroundColor: '#6E5494',
|
||||
color: '#6E5494',
|
||||
fontSize: 12,
|
||||
iconWidth: 16,
|
||||
// iconFontSize: 16,
|
||||
},
|
||||
[Operator.DuckDuckGo]: {
|
||||
backgroundColor: '#e7e389',
|
||||
@ -235,10 +236,14 @@ export const operatorMap: Record<
|
||||
backgroundColor: '#f5e8e6',
|
||||
},
|
||||
[Operator.GitHub]: {
|
||||
backgroundColor: '#c7c7f8',
|
||||
backgroundColor: 'purple',
|
||||
color: 'purple',
|
||||
},
|
||||
[Operator.BaiduFanyi]: { backgroundColor: '#e5f2d3' },
|
||||
[Operator.QWeather]: { backgroundColor: '#a4bbf3' },
|
||||
[Operator.QWeather]: {
|
||||
backgroundColor: '#a4bbf3',
|
||||
color: '#a4bbf3',
|
||||
},
|
||||
[Operator.ExeSQL]: { backgroundColor: '#b9efe8' },
|
||||
[Operator.Switch]: { backgroundColor: '#dbaff6', color: '#dbaff6' },
|
||||
[Operator.WenCai]: { backgroundColor: '#faac5b' },
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
.dynamicInputVariable {
|
||||
background-color: #ebe9e9;
|
||||
background-color: #ebe9e950;
|
||||
:global(.ant-collapse-content) {
|
||||
background-color: #f6f6f6;
|
||||
background-color: #f6f6f657;
|
||||
}
|
||||
:global(.ant-collapse-content-box) {
|
||||
padding: 0 !important;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
.dynamicInputVariable {
|
||||
background-color: #ebe9e9;
|
||||
background-color: #ebe9e950;
|
||||
:global(.ant-collapse-content) {
|
||||
background-color: #f6f6f6;
|
||||
background-color: #f6f6f657;
|
||||
}
|
||||
margin-bottom: 20px;
|
||||
.title {
|
||||
|
||||
@ -18,9 +18,9 @@
|
||||
}
|
||||
|
||||
.dynamicParameterVariable {
|
||||
background-color: #ebe9e9;
|
||||
background-color: #ebe9e950;
|
||||
:global(.ant-collapse-content) {
|
||||
background-color: #f6f6f6;
|
||||
background-color: #f6f6f634;
|
||||
}
|
||||
:global(.ant-collapse-content-box) {
|
||||
padding: 0 !important;
|
||||
|
||||
@ -27,7 +27,8 @@
|
||||
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(234, 236, 240, 1);
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
||||
padding: 24px;
|
||||
width: 300px;
|
||||
@ -39,14 +40,12 @@
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
word-break: break-all;
|
||||
}
|
||||
.description {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +71,6 @@
|
||||
.rightText {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
font-style: normal;
|
||||
font-weight: @fontWeight600;
|
||||
line-height: 38px;
|
||||
color: rgba(16, 24, 40, 1);
|
||||
color: var(--ant-color-info);
|
||||
}
|
||||
.description {
|
||||
font-family: Inter;
|
||||
@ -25,7 +25,6 @@
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
color: rgba(71, 84, 103, 1);
|
||||
}
|
||||
|
||||
.topButton {
|
||||
|
||||
@ -51,31 +51,50 @@
|
||||
line-height: 20px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
.titledark {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-weight: 600;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.descriptiondark {
|
||||
margin-top: 4px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(234, 236, 240, 1);
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
||||
padding: 24px;
|
||||
width: 300px;
|
||||
cursor: pointer;
|
||||
|
||||
.titleWrapper {
|
||||
// flex: 1;
|
||||
.title {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
word-break: break-all;
|
||||
}
|
||||
.description {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,7 +120,6 @@
|
||||
.rightText {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'umi';
|
||||
|
||||
import OperateDropdown from '@/components/operate-dropdown';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { useDeleteKnowledge } from '@/hooks/knowledge-hooks';
|
||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||
import styles from './index.less';
|
||||
@ -24,7 +25,7 @@ const KnowledgeCard = ({ item }: IProps) => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const { data: userInfo } = useFetchUserInfo();
|
||||
|
||||
const { theme } = useTheme();
|
||||
const { deleteKnowledge } = useDeleteKnowledge();
|
||||
|
||||
const removeKnowledge = async () => {
|
||||
@ -52,8 +53,18 @@ const KnowledgeCard = ({ item }: IProps) => {
|
||||
<OperateDropdown deleteItem={removeKnowledge}></OperateDropdown>
|
||||
</div>
|
||||
<div className={styles.titleWrapper}>
|
||||
<span className={styles.title}>{item.name}</span>
|
||||
<p className={styles.description}>{item.description}</p>
|
||||
<span
|
||||
className={theme === 'dark' ? styles.titledark : styles.title}
|
||||
>
|
||||
{item.name}
|
||||
</span>
|
||||
<p
|
||||
className={
|
||||
theme === 'dark' ? styles.descriptiondark : styles.description
|
||||
}
|
||||
>
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<div className={styles.footerTop}>
|
||||
|
||||
@ -2,10 +2,12 @@
|
||||
|
||||
.loginPage {
|
||||
display: flex;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
|
||||
.loginLeft {
|
||||
// width: 610px;
|
||||
width: 40%;
|
||||
background-color: #fff;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -39,7 +41,6 @@
|
||||
z-index: -1;
|
||||
}
|
||||
.white {
|
||||
color: #fff;
|
||||
}
|
||||
.pink {
|
||||
color: #e9d7fe;
|
||||
@ -87,15 +88,12 @@
|
||||
span {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
|
||||
color: #000000a6;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 957px) {
|
||||
.loginLeft {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
@ -15,16 +15,8 @@
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// .mainLayout {
|
||||
// background: transparent;
|
||||
// }
|
||||
}
|
||||
|
||||
// .transparentSearchSide {
|
||||
// background-color: rgb(251 251 251 / 88%) !important;
|
||||
// }
|
||||
|
||||
.searchSide {
|
||||
position: relative;
|
||||
max-width: 400px !important;
|
||||
@ -101,10 +93,10 @@
|
||||
}
|
||||
.answerWrapper {
|
||||
margin-top: 16px;
|
||||
background: rgb(232 242 251 / 70%);
|
||||
background: rgba(232 242 251, 1);
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
:global(.ant-card-head) {
|
||||
background-color: #e6f4ff;
|
||||
background-color: #e6f4ff23;
|
||||
}
|
||||
& p {
|
||||
margin: 0;
|
||||
|
||||
@ -146,9 +146,9 @@ const SearchPage = () => {
|
||||
></RetrievalDocuments>
|
||||
<Divider></Divider>
|
||||
<Spin spinning={loading}>
|
||||
{chunks.length > 0 && (
|
||||
{chunks?.length > 0 && (
|
||||
<List
|
||||
dataSource={chunks}
|
||||
dataSource={chunks || []}
|
||||
className={styles.chunks}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
|
||||
@ -1,19 +1,21 @@
|
||||
import { ReactComponent as ApiIcon } from '@/assets/svg/api.svg';
|
||||
import { ReactComponent as LogoutIcon } from '@/assets/svg/logout.svg';
|
||||
import { ReactComponent as ModelIcon } from '@/assets/svg/model-providers.svg';
|
||||
import { ReactComponent as PasswordIcon } from '@/assets/svg/password.svg';
|
||||
import { ReactComponent as ProfileIcon } from '@/assets/svg/profile.svg';
|
||||
import { ReactComponent as TeamIcon } from '@/assets/svg/team.svg';
|
||||
import {
|
||||
ApiIcon,
|
||||
LogOutIcon,
|
||||
ModelProviderIcon,
|
||||
PasswordIcon,
|
||||
ProfileIcon,
|
||||
TeamIcon,
|
||||
} from '@/assets/icon/Icon';
|
||||
import { UserSettingRouteKey } from '@/constants/setting';
|
||||
import { MonitorOutlined } from '@ant-design/icons';
|
||||
|
||||
export const UserSettingIconMap = {
|
||||
[UserSettingRouteKey.Profile]: <ProfileIcon />,
|
||||
[UserSettingRouteKey.Password]: <PasswordIcon />,
|
||||
[UserSettingRouteKey.Model]: <ModelIcon />,
|
||||
[UserSettingRouteKey.Model]: <ModelProviderIcon />,
|
||||
[UserSettingRouteKey.System]: <MonitorOutlined style={{ fontSize: 24 }} />,
|
||||
[UserSettingRouteKey.Team]: <TeamIcon />,
|
||||
[UserSettingRouteKey.Logout]: <LogoutIcon />,
|
||||
[UserSettingRouteKey.Logout]: <LogOutIcon />,
|
||||
[UserSettingRouteKey.Api]: <ApiIcon />,
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
import { Table } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import React from 'react';
|
||||
|
||||
type TranslationTableRow = {
|
||||
key: string;
|
||||
[language: string]: string;
|
||||
};
|
||||
|
||||
interface TranslationTableProps {
|
||||
data: TranslationTableRow[];
|
||||
languages: string[];
|
||||
}
|
||||
|
||||
const TranslationTable: React.FC<TranslationTableProps> = ({
|
||||
data,
|
||||
languages,
|
||||
}) => {
|
||||
// Define columns dynamically based on languages
|
||||
const columns: ColumnsType<TranslationTableRow> = [
|
||||
{
|
||||
title: 'Key',
|
||||
dataIndex: 'key',
|
||||
key: 'key',
|
||||
fixed: 'left',
|
||||
width: 200,
|
||||
sorter: (a, b) => a.key.localeCompare(b.key), // Sorting by key
|
||||
},
|
||||
...languages.map((lang) => ({
|
||||
title: lang,
|
||||
dataIndex: lang,
|
||||
key: lang,
|
||||
sorter: (a: any, b: any) => a[lang].localeCompare(b[lang]), // Sorting by language
|
||||
// Example filter for each language
|
||||
filters: [
|
||||
{
|
||||
text: 'Show Empty',
|
||||
value: 'show_empty',
|
||||
},
|
||||
{
|
||||
text: 'Show Non-Empty',
|
||||
value: 'show_non_empty',
|
||||
},
|
||||
],
|
||||
onFilter: (value: any, record: any) => {
|
||||
if (value === 'show_empty') {
|
||||
return !record[lang]; // Show rows with empty translations
|
||||
}
|
||||
if (value === 'show_non_empty') {
|
||||
return record[lang] && record[lang].length > 0; // Show rows with non-empty translations
|
||||
}
|
||||
return true;
|
||||
},
|
||||
})),
|
||||
];
|
||||
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
rowKey="key"
|
||||
pagination={{ pageSize: 10 }}
|
||||
scroll={{ x: true }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default TranslationTable;
|
||||
13
web/src/pages/user-setting/setting-locale/index.tsx
Normal file
13
web/src/pages/user-setting/setting-locale/index.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { translationTable } from '@/locales/config';
|
||||
import TranslationTable from './TranslationTable';
|
||||
|
||||
function UserSettingLocale() {
|
||||
return (
|
||||
<TranslationTable
|
||||
data={translationTable}
|
||||
languages={['English', 'Vietnamese', 'Spanish', 'zh', 'zh-TRADITIONAL']}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserSettingLocale;
|
||||
@ -24,12 +24,30 @@
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.toBeAddedCardDark {
|
||||
border-radius: 24px;
|
||||
border: 1px solid #eaecf0;
|
||||
background: #e3f0ff2a;
|
||||
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
||||
:global(.ant-card-body) {
|
||||
padding: 10px 24px;
|
||||
}
|
||||
.addButton {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.addedCard {
|
||||
border-radius: 18px;
|
||||
border: 1px solid #eaecf0;
|
||||
background: #e6e7eb;
|
||||
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
||||
}
|
||||
.addedCardDark {
|
||||
border-radius: 18px;
|
||||
border: 1px solid #eaecf0;
|
||||
background: #e6e7eb21;
|
||||
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
||||
}
|
||||
.modelDivider {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { ReactComponent as MoreModelIcon } from '@/assets/svg/more-model.svg';
|
||||
import { LlmIcon } from '@/components/svg-icon';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
|
||||
import { LlmItem, useSelectLlmList } from '@/hooks/llm-hooks';
|
||||
import { CloseCircleOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
@ -61,6 +62,7 @@ interface IModelCardProps {
|
||||
const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
||||
const { visible, switchVisible } = useSetModalState();
|
||||
const { t } = useTranslate('setting');
|
||||
const { theme } = useTheme();
|
||||
const { handleDeleteLlm } = useHandleDeleteLlm(item.name);
|
||||
const { handleDeleteFactory } = useHandleDeleteFactory(item.name);
|
||||
|
||||
@ -74,7 +76,9 @@ const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
||||
|
||||
return (
|
||||
<List.Item>
|
||||
<Card className={styles.addedCard}>
|
||||
<Card
|
||||
className={theme === 'dark' ? styles.addedCardDark : styles.addedCard}
|
||||
>
|
||||
<Row align={'middle'}>
|
||||
<Col span={12}>
|
||||
<Flex gap={'middle'} align="center">
|
||||
@ -139,6 +143,7 @@ const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
||||
|
||||
const UserSettingModel = () => {
|
||||
const { factoryList, myLlmList: llmList, loading } = useSelectLlmList();
|
||||
const { theme } = useTheme();
|
||||
const {
|
||||
saveApiKeyLoading,
|
||||
initialApiKey,
|
||||
@ -313,7 +318,13 @@ const UserSettingModel = () => {
|
||||
dataSource={factoryList}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
<Card className={styles.toBeAddedCard}>
|
||||
<Card
|
||||
className={
|
||||
theme === 'dark'
|
||||
? styles.toBeAddedCardDark
|
||||
: styles.toBeAddedCard
|
||||
}
|
||||
>
|
||||
<Flex vertical gap={'middle'}>
|
||||
<LlmIcon name={item.name} />
|
||||
<Flex vertical gap={'middle'}>
|
||||
|
||||
Reference in New Issue
Block a user