Merge pull request #423 from SuanmoSuanyangTechnology/release/v0.2.5

Release/v0.2.5
This commit is contained in:
Ke Sun
2026-02-28 18:38:18 +08:00
committed by GitHub
11 changed files with 84 additions and 26 deletions

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 16:50:10
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 16:50:10
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-27 10:20:51
*/
/**
* Model List View
@@ -21,7 +21,7 @@ import PageEmpty from '@/components/Empty/PageEmpty';
import Tag from '@/components/Tag';
import KeyConfigModal from './components/KeyConfigModal'
import ModelListDetail from './components/ModelListDetail'
import { getLogoUrl } from './utils'
import { getListLogoUrl } from './utils'
/**
* Model list component
@@ -70,7 +70,7 @@ const ModelList = forwardRef<BaseRef, { query: any; handleEdit: (vo?: ModelListI
<RbCard
key={item.provider}
title={t(`modelNew.${item.provider}`)}
avatarUrl={getLogoUrl(item.logo)}
avatarUrl={getListLogoUrl(item.provider, item.logo)}
avatar={
<div className="rb:w-12 rb:h-12 rb:rounded-lg rb:mr-3.25 rb:bg-[#155eef] rb:flex rb:items-center rb:justify-center rb:text-[28px] rb:text-[#ffffff]">
{item.provider[0].toUpperCase()}

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 16:49:28
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 16:49:28
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-28 17:24:05
*/
/**
* Custom Model Modal
@@ -50,7 +50,7 @@ const CustomModelModal = forwardRef<CustomModelModalRef, CustomModelModalProps>(
setModel(model);
form.setFieldsValue({
...model,
logo: model.logo ? { url: model.logo, uid: model.logo, status: 'done', name: 'logo' } : undefined
logo: model.logo && model.logo.startsWith('http') ? { url: model.logo, uid: model.logo, status: 'done', name: 'logo' } : undefined
});
} else {
setIsEdit(false);

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 16:50:22
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 16:50:22
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-27 10:22:46
*/
/**
* Utility functions for Model Management
@@ -40,5 +40,26 @@ export const getLogoUrl = (logo?: string) => {
return logo
}
return ICONS[logo as keyof typeof ICONS] || undefined
}
/**
* Get logo URL from provider name or URL
* @param provider - Provider name
* @param logo - Provider name or logo URL
* @returns Logo URL or undefined
*/
export const getListLogoUrl = (provider?: string, logo?: string) => {
let url = ICONS[provider as keyof typeof ICONS]
if (url) return url
if (!logo) {
return undefined
}
if (logo.startsWith('http')) {
return logo
}
return ICONS[logo as keyof typeof ICONS] || undefined
}

View File

@@ -34,8 +34,8 @@ interface SpaceModalProps {
}
/** Storage types */
const types: StorageType[] = [
'rag',
'neo4j',
'rag',
]
/** Type icons mapping */
const typeIcons: Record<StorageType, string> = {
@@ -154,6 +154,9 @@ const SpaceModal = forwardRef<SpaceModalRef, SpaceModalProps>(({
<Form
form={form}
layout="vertical"
initialValues={{
storage_type: types[0],
}}
>
<Form.Item
name="icon"
@@ -183,7 +186,8 @@ const SpaceModal = forwardRef<SpaceModalRef, SpaceModalProps>(({
value: type,
label: t(`space.${type}`),
labelDesc: t(`space.${type}Desc`),
icon: typeIcons[type]
icon: typeIcons[type],
recommend: type === 'neo4j',
}))}
block={true}
/>

View File

@@ -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 { $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 [selectedIndex, setSelectedIndex] = useState(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(() => {
return editor.registerUpdateListener(({ editorState }) => {
@@ -116,7 +136,7 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
setShowSuggestions(false);
};
const groupedSuggestions = options.reduce((groups: Record<string, any[]>, suggestion) => {
const groupedSuggestions = options.reduce((groups: Record<string, Suggestion[]>, suggestion) => {
const { nodeData } = suggestion
const nodeId = nodeData.id as string;
if (!groups[nodeId]) {
@@ -163,7 +183,9 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
while (nextIndex < allOptions.length && allOptions[nextIndex].disabled) {
nextIndex++;
}
return nextIndex >= allOptions.length ? prev : nextIndex;
const newIndex = nextIndex >= allOptions.length ? prev : nextIndex;
setTimeout(() => scrollSelectedIntoView(), 0);
return newIndex;
});
return true;
}
@@ -182,7 +204,9 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
while (prevIndex >= 0 && allOptions[prevIndex].disabled) {
prevIndex--;
}
return prevIndex < 0 ? prev : prevIndex;
const newIndex = prevIndex < 0 ? prev : prevIndex;
setTimeout(() => scrollSelectedIntoView(), 0);
return newIndex;
});
return true;
}
@@ -218,6 +242,7 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
}
return (
<div
ref={popupRef}
data-autocomplete-popup="true"
onMouseDown={(e) => e.preventDefault()}
style={{
@@ -248,6 +273,7 @@ const AutocompletePlugin: FC<{ options: Suggestion[], enableJinja2?: boolean }>
return (
<div
key={option.key}
data-selected={selectedIndex === globalIndex}
style={{
padding: '8px 12px',
cursor: option.disabled ? 'not-allowed' : 'pointer',