perf: variable label picker scroll & focus disappear (#2135)

* fix: variable label picker scroll & focus disappear

* fix

* fix filter

* revert
This commit is contained in:
heheer
2024-07-23 18:03:53 +08:00
committed by GitHub
parent f37cdabb15
commit bf5145e632
10 changed files with 39 additions and 17 deletions

View File

@@ -240,7 +240,7 @@ export function replaceVariableLabel({
variables: Record<string, string | number>;
runningNode: RuntimeNodeItemType;
}) {
if (!(typeof text === 'string')) return text;
if (typeof text !== 'string') return text;
const globalVariables = Object.keys(variables).map((key) => {
return {

View File

@@ -292,14 +292,14 @@ async function fetchData({
function replaceVariable(text: string, obj: Record<string, any>) {
for (const [key, value] of Object.entries(obj)) {
if (value === undefined) {
text = text.replace(new RegExp(`{{${key}}}`, 'g'), UNDEFINED_SIGN);
text = text.replace(new RegExp(`{{(${key})}}`, 'g'), UNDEFINED_SIGN);
} else {
const replacement = JSON.stringify(value);
const unquotedReplacement =
replacement.startsWith('"') && replacement.endsWith('"')
? replacement.slice(1, -1)
: replacement;
text = text.replace(new RegExp(`{{${key}}}`, 'g'), unquotedReplacement);
text = text.replace(new RegExp(`{{(${key})}}`, 'g'), unquotedReplacement);
}
}
return text || '';

View File

@@ -129,7 +129,7 @@ export default function Editor({
});
}}
/>
<VariableLabelPickerPlugin variables={variables} />
<VariableLabelPickerPlugin variables={variables} isFocus={focus} />
<VariablePlugin variables={variables} />
<VariableLabelPlugin variables={variables} />
<OnBlurPlugin onBlur={onBlur} />

View File

@@ -27,13 +27,18 @@ interface TransformedParent {
}
export default function VariableLabelPickerPlugin({
variables
variables,
isFocus
}: {
variables: EditorVariablePickerType[];
isFocus: boolean;
}) {
const { t } = useTranslation();
const [editor] = useLexicalComposerContext();
const [queryString, setQueryString] = useState<string | null>(null);
const [currentIndex, setCurrentIndex] = useState<number>(0);
const [highlightIndex, setHighlightIndex] = useState<number | null>(null);
const highlightedItemRef = React.useRef<any>(null);
const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('/', {
minLength: 0
@@ -58,6 +63,15 @@ export default function VariableLabelPickerPlugin({
[editor]
);
React.useEffect(() => {
if (highlightedItemRef.current) {
highlightedItemRef.current.scrollIntoView({
behavior: 'auto',
block: 'end'
});
}
}, [currentIndex]);
return (
<LexicalTypeaheadMenuPlugin
onQueryChange={setQueryString}
@@ -71,7 +85,11 @@ export default function VariableLabelPickerPlugin({
if (anchorElementRef.current == null) {
return null;
}
return anchorElementRef.current && variables.length
if (currentIndex !== selectedIndex) {
setCurrentIndex(selectedIndex || 0);
setHighlightIndex(selectedIndex || 0);
}
return anchorElementRef.current && variables.length && isFocus
? ReactDOM.createPortal(
<Box
bg={'white'}
@@ -123,7 +141,7 @@ export default function VariableLabelPickerPlugin({
{item.label}
</Box>
</Flex>
{item.children?.map((child, index) => (
{item.children?.map((child) => (
<Flex
alignItems={'center'}
as={'li'}
@@ -136,7 +154,8 @@ export default function VariableLabelPickerPlugin({
_notLast={{
mb: 1
}}
{...(selectedIndex === child.index
ref={selectedIndex === child.index ? highlightedItemRef : null}
{...(highlightIndex === child.index
? {
bg: '#1118240D',
color: 'primary.700'
@@ -145,12 +164,11 @@ export default function VariableLabelPickerPlugin({
bg: 'white',
color: 'myGray.600'
})}
onClick={() => {
setHighlightedIndex(child.index);
onMouseDown={() => {
selectOptionAndCleanUp({ ...child, parent: item });
}}
onMouseEnter={() => {
setHighlightedIndex(child.index);
setHighlightIndex(child.index);
}}
>
<Box ml={2} fontSize={'sm'} whiteSpace={'nowrap'}>

View File

@@ -221,7 +221,7 @@ export function getHashtagRegexString(): string {
const hashtag =
`(${hashLeftCharList})` +
`(${hashLeftCharList})` +
`(${hashMiddleCharList})([a-zA-Z0-9_\\.]{0,29})(${hashMiddleCharList})` +
`(${hashMiddleCharList})([a-zA-Z0-9_\\.]{0,100})(${hashMiddleCharList})` +
`(${hashRightCharList})(${hashRightCharList})`;
return hashtag;

View File

@@ -35,6 +35,7 @@ type useChatStoreType = OutLinkChatAuthProps &
ChatProviderProps & {
welcomeText: string;
variableList: VariableItemType[];
allVariableList: VariableItemType[];
questionGuide: boolean;
ttsConfig: AppTTSConfigType;
whisperConfig: AppWhisperConfigType;
@@ -189,6 +190,7 @@ const Provider = ({
teamToken,
welcomeText,
variableList: variables.filter((item) => item.type !== VariableInputEnum.custom),
allVariableList: variables,
questionGuide,
ttsConfig,
whisperConfig,

View File

@@ -21,7 +21,7 @@ const VariableInput = ({
const { t } = useTranslation();
const { appAvatar, variableList, variablesForm } = useContextSelector(ChatBoxContext, (v) => v);
const { register, getValues, setValue, handleSubmit: handleSubmitChat, control } = variablesForm;
const { register, setValue, handleSubmit: handleSubmitChat, control } = variablesForm;
return (
<Box py={3}>

View File

@@ -140,6 +140,7 @@ const ChatBox = (
const {
welcomeText,
variableList,
allVariableList,
questionGuide,
startSegmentedAudio,
finishSegmentedAudio,
@@ -390,7 +391,7 @@ const ChatBox = (
// delete invalid variables 只保留在 variableList 中的变量
const requestVariables: Record<string, any> = {};
variableList?.forEach((item) => {
allVariableList?.forEach((item) => {
requestVariables[item.key] = variables[item.key] || '';
});

View File

@@ -10,7 +10,6 @@ import {
storeNodes2RuntimeNodes
} from '@fastgpt/global/core/workflow/runtime/utils';
import { useMemoizedFn } from 'ahooks';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
import { useContextSelector } from 'use-context-selector';
import { AppContext } from './context';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
@@ -21,6 +20,7 @@ import dynamic from 'next/dynamic';
import { useChat } from '@/components/core/chat/ChatContainer/useChat';
import { Box } from '@chakra-ui/react';
import ChatBox from '@/components/core/chat/ChatContainer/ChatBox';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
const PluginRunBox = dynamic(() => import('@/components/core/chat/ChatContainer/PluginRunBox'));

View File

@@ -132,8 +132,9 @@ const MyApps = () => {
</Box>
)}
<Flex gap={5} flex={'1 0 0'} h={0}>
<Box
<Flex
flex={'1 0 0'}
flexDirection={'column'}
h={'100%'}
pr={folderDetail ? [4, 2] : [4, 10]}
pl={3}
@@ -237,7 +238,7 @@ const MyApps = () => {
<MyBox flex={'1 0 0'} isLoading={myApps.length === 0 && isFetchingApps}>
<List />
</MyBox>
</Box>
</Flex>
{/* Folder slider */}
{!!folderDetail && isPc && (