Merge pull request #414 from SuanmoSuanyangTechnology/fix/release_web_zy
Fix/release web zy
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
import { type FC, type Key, type ReactNode, useEffect } from 'react';
|
import { type FC, type Key, type ReactNode, useEffect } from 'react';
|
||||||
import { type RadioGroupProps } from 'antd';
|
import { type RadioGroupProps } from 'antd';
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
/** Radio card option interface */
|
/** Radio card option interface */
|
||||||
interface RadioCardOption {
|
interface RadioCardOption {
|
||||||
@@ -33,6 +34,8 @@ interface RadioCardOption {
|
|||||||
icon?: string;
|
icon?: string;
|
||||||
/** Whether the option is disabled */
|
/** Whether the option is disabled */
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
/** Whether the option is recommended */
|
||||||
|
recommend?: boolean;
|
||||||
/** Additional properties */
|
/** Additional properties */
|
||||||
[key: string]: string | number | boolean | undefined | null | Key;
|
[key: string]: string | number | boolean | undefined | null | Key;
|
||||||
}
|
}
|
||||||
@@ -63,6 +66,7 @@ const RadioGroupCard: FC<RadioCardProps> = ({
|
|||||||
allowClear = true,
|
allowClear = true,
|
||||||
block = false,
|
block = false,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
/** Listen to value changes and trigger side effects via onValueChange callback */
|
/** Listen to value changes and trigger side effects via onValueChange callback */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onValueChange) {
|
if (onValueChange) {
|
||||||
@@ -91,12 +95,13 @@ const RadioGroupCard: FC<RadioCardProps> = ({
|
|||||||
})}>
|
})}>
|
||||||
{/* Render each option as a selectable card */}
|
{/* Render each option as a selectable card */}
|
||||||
{options.map(option => (
|
{options.map(option => (
|
||||||
<div key={String(option.value)} className={clsx("rb:border rb:rounded-lg rb:w-full rb:p-[20px_12px] rb:text-center rb:cursor-pointer", {
|
<div key={String(option.value)} className={clsx("rb:relative rb:border rb:rounded-lg rb:w-full rb:p-[20px_12px] rb:text-center rb:cursor-pointer", {
|
||||||
'rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF]': option.value === value,
|
'rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF]': option.value === value,
|
||||||
'rb:border-[#EBEBEB] rb:bg-[#ffffff]': option.value !== value,
|
'rb:border-[#EBEBEB] rb:bg-[#ffffff]': option.value !== value,
|
||||||
'rb:opacity-[0.75]': option.disabled,
|
'rb:opacity-[0.75]': option.disabled,
|
||||||
'rb:flex rb:items-center rb:text-left rb:gap-4': block,
|
'rb:flex rb:items-center rb:text-left rb:gap-4': block,
|
||||||
})} onClick={() => handleChange(option)}>
|
})} onClick={() => handleChange(option)}>
|
||||||
|
{option.recommend && <div className="rb:absolute rb:right-0 rb:top-0 rb:bg-[#FF5D34] rb:rounded-[0px_7px_0px_8px] rb:text-[12px] rb:text-white rb:font-regular rb:leading-4 rb:p-[4px_8px]">{t('common.recommend')}</div>}
|
||||||
{/* Use custom render or default card layout */}
|
{/* Use custom render or default card layout */}
|
||||||
{itemRender ? itemRender(option) : (
|
{itemRender ? itemRender(option) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -452,6 +452,7 @@ export const en = {
|
|||||||
nextStep: 'Next Step',
|
nextStep: 'Next Step',
|
||||||
prevStep: 'Previous Step',
|
prevStep: 'Previous Step',
|
||||||
exportSuccess: 'Export successful',
|
exportSuccess: 'Export successful',
|
||||||
|
recommend: 'Recommend',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
searchPlaceholder: 'search model…',
|
searchPlaceholder: 'search model…',
|
||||||
|
|||||||
@@ -1019,6 +1019,7 @@ export const zh = {
|
|||||||
nextStep: '下一步',
|
nextStep: '下一步',
|
||||||
prevStep: '上一步',
|
prevStep: '上一步',
|
||||||
exportSuccess: '导出成功',
|
exportSuccess: '导出成功',
|
||||||
|
recommend: '推荐',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
searchPlaceholder: '搜索模型…',
|
searchPlaceholder: '搜索模型…',
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ interface SpaceModalProps {
|
|||||||
}
|
}
|
||||||
/** Storage types */
|
/** Storage types */
|
||||||
const types: StorageType[] = [
|
const types: StorageType[] = [
|
||||||
'rag',
|
|
||||||
'neo4j',
|
'neo4j',
|
||||||
|
'rag',
|
||||||
]
|
]
|
||||||
/** Type icons mapping */
|
/** Type icons mapping */
|
||||||
const typeIcons: Record<StorageType, string> = {
|
const typeIcons: Record<StorageType, string> = {
|
||||||
@@ -154,6 +154,9 @@ const SpaceModal = forwardRef<SpaceModalRef, SpaceModalProps>(({
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
|
initialValues={{
|
||||||
|
storage_type: types[0],
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="icon"
|
name="icon"
|
||||||
@@ -183,7 +186,8 @@ const SpaceModal = forwardRef<SpaceModalRef, SpaceModalProps>(({
|
|||||||
value: type,
|
value: type,
|
||||||
label: t(`space.${type}`),
|
label: t(`space.${type}`),
|
||||||
labelDesc: t(`space.${type}Desc`),
|
labelDesc: t(`space.${type}Desc`),
|
||||||
icon: typeIcons[type]
|
icon: typeIcons[type],
|
||||||
|
recommend: type === 'neo4j',
|
||||||
}))}
|
}))}
|
||||||
block={true}
|
block={true}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState, type FC } from 'react';
|
import { useEffect, useState, useRef, type FC } from 'react';
|
||||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
||||||
import { $getSelection, $isRangeSelection, $isTextNode, COMMAND_PRIORITY_HIGH, KEY_ENTER_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND } from 'lexical';
|
import { $getSelection, $isRangeSelection, $isTextNode, COMMAND_PRIORITY_HIGH, KEY_ENTER_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND } from 'lexical';
|
||||||
|
|
||||||
@@ -22,6 +22,26 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
|
|||||||
const [showSuggestions, setShowSuggestions] = useState(false);
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
||||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||||
const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0 });
|
const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0 });
|
||||||
|
const popupRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const scrollSelectedIntoView = () => {
|
||||||
|
if (!popupRef.current) return;
|
||||||
|
|
||||||
|
const selectedElement = popupRef.current.querySelector('[data-selected="true"]');
|
||||||
|
if (!selectedElement) return;
|
||||||
|
|
||||||
|
const container = popupRef.current;
|
||||||
|
const element = selectedElement as HTMLElement;
|
||||||
|
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const elementRect = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (elementRect.bottom > containerRect.bottom) {
|
||||||
|
container.scrollTop += elementRect.bottom - containerRect.bottom;
|
||||||
|
} else if (elementRect.top < containerRect.top) {
|
||||||
|
container.scrollTop -= containerRect.top - elementRect.top;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return editor.registerUpdateListener(({ editorState }) => {
|
return editor.registerUpdateListener(({ editorState }) => {
|
||||||
@@ -116,7 +136,7 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
|
|||||||
setShowSuggestions(false);
|
setShowSuggestions(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupedSuggestions = options.reduce((groups: Record<string, any[]>, suggestion) => {
|
const groupedSuggestions = options.reduce((groups: Record<string, Suggestion[]>, suggestion) => {
|
||||||
const { nodeData } = suggestion
|
const { nodeData } = suggestion
|
||||||
const nodeId = nodeData.id as string;
|
const nodeId = nodeData.id as string;
|
||||||
if (!groups[nodeId]) {
|
if (!groups[nodeId]) {
|
||||||
@@ -163,7 +183,9 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
|
|||||||
while (nextIndex < allOptions.length && allOptions[nextIndex].disabled) {
|
while (nextIndex < allOptions.length && allOptions[nextIndex].disabled) {
|
||||||
nextIndex++;
|
nextIndex++;
|
||||||
}
|
}
|
||||||
return nextIndex >= allOptions.length ? prev : nextIndex;
|
const newIndex = nextIndex >= allOptions.length ? prev : nextIndex;
|
||||||
|
setTimeout(() => scrollSelectedIntoView(), 0);
|
||||||
|
return newIndex;
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -182,7 +204,9 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
|
|||||||
while (prevIndex >= 0 && allOptions[prevIndex].disabled) {
|
while (prevIndex >= 0 && allOptions[prevIndex].disabled) {
|
||||||
prevIndex--;
|
prevIndex--;
|
||||||
}
|
}
|
||||||
return prevIndex < 0 ? prev : prevIndex;
|
const newIndex = prevIndex < 0 ? prev : prevIndex;
|
||||||
|
setTimeout(() => scrollSelectedIntoView(), 0);
|
||||||
|
return newIndex;
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -218,6 +242,7 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={popupRef}
|
||||||
data-autocomplete-popup="true"
|
data-autocomplete-popup="true"
|
||||||
onMouseDown={(e) => e.preventDefault()}
|
onMouseDown={(e) => e.preventDefault()}
|
||||||
style={{
|
style={{
|
||||||
@@ -248,6 +273,7 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={option.key}
|
key={option.key}
|
||||||
|
data-selected={selectedIndex === globalIndex}
|
||||||
style={{
|
style={{
|
||||||
padding: '8px 12px',
|
padding: '8px 12px',
|
||||||
cursor: option.disabled ? 'not-allowed' : 'pointer',
|
cursor: option.disabled ? 'not-allowed' : 'pointer',
|
||||||
|
|||||||
Reference in New Issue
Block a user