From abdc78e12310e539d24c11bf71b51f990835b00b Mon Sep 17 00:00:00 2001 From: jialin Date: Fri, 25 Oct 2024 18:34:33 +0800 Subject: [PATCH] fix(style): text overflow --- config/config.ts | 2 +- src/components/auto-tooltip/index.tsx | 25 +++--- src/components/auto-tooltip/title-tip.tsx | 31 ++++++++ src/components/highlight-code/code-viewer.tsx | 1 + src/components/logs-viewer/index.less | 2 + src/components/logs-viewer/index.tsx | 15 ++-- src/components/version-info/index.tsx | 2 +- .../components/resource-utilization.tsx | 5 -- src/pages/llmodels/components/model-card.tsx | 4 +- .../playground/components/ground-left.tsx | 15 ++-- .../playground/components/message-input.tsx | 6 ++ .../components/multiple-chat/content-item.tsx | 5 ++ .../components/multiple-chat/model-item.tsx | 29 +++++-- .../playground/components/view-code-modal.tsx | 76 ++++--------------- 14 files changed, 119 insertions(+), 99 deletions(-) create mode 100644 src/components/auto-tooltip/title-tip.tsx diff --git a/config/config.ts b/config/config.ts index 757ea595..36546891 100644 --- a/config/config.ts +++ b/config/config.ts @@ -14,7 +14,7 @@ const isProduction = env === 'production'; const t = Date.now(); export default defineConfig({ proxy: { - ...proxy('http://192.168.50.3') + ...proxy() }, history: { type: 'hash' diff --git a/src/components/auto-tooltip/index.tsx b/src/components/auto-tooltip/index.tsx index 7f7ba87c..716b4350 100644 --- a/src/components/auto-tooltip/index.tsx +++ b/src/components/auto-tooltip/index.tsx @@ -1,5 +1,5 @@ import { Tag, Tooltip, type TagProps } from 'antd'; -import debounce from 'lodash/debounce'; +import { throttle } from 'lodash'; import React, { useCallback, useEffect, @@ -7,6 +7,7 @@ import React, { useRef, useState } from 'react'; +import TitleTip from './title-tip'; // type TagProps = React.ComponentProps; @@ -34,6 +35,7 @@ const AutoTooltip: React.FC = ({ }) => { const contentRef = useRef(null); const [isOverflowing, setIsOverflowing] = useState(false); + const resizeObserver = useRef(); const checkOverflow = useCallback(() => { if (contentRef.current) { @@ -42,19 +44,14 @@ const AutoTooltip: React.FC = ({ } }, [contentRef.current]); - const debouncedCheckOverflow = useMemo( - () => debounce(checkOverflow, 200), - [checkOverflow] - ); - useEffect(() => { - checkOverflow(); + const debouncedCheckOverflow = throttle(checkOverflow, 200); window.addEventListener('resize', debouncedCheckOverflow); return () => { window.removeEventListener('resize', debouncedCheckOverflow); debouncedCheckOverflow.cancel(); }; - }, [checkOverflow, debouncedCheckOverflow]); + }, [checkOverflow]); useEffect(() => { checkOverflow(); @@ -74,7 +71,17 @@ const AutoTooltip: React.FC = ({ return ( + {children} + + } {...tooltipProps} > {ghost ? ( diff --git a/src/components/auto-tooltip/title-tip.tsx b/src/components/auto-tooltip/title-tip.tsx new file mode 100644 index 00000000..ecb5e876 --- /dev/null +++ b/src/components/auto-tooltip/title-tip.tsx @@ -0,0 +1,31 @@ +import useOverlayScroller from '@/hooks/use-overlay-scroller'; +import React from 'react'; + +interface TitleTipProps { + isOverflowing: boolean; + showTitle: boolean; + title: React.ReactNode; + children: React.ReactNode; +} + +const TitleTip: React.FC = (props) => { + const { isOverflowing, showTitle, title, children } = props; + const { initialize } = useOverlayScroller(); + const scrollRef = React.useRef(null); + + React.useEffect(() => { + if (scrollRef.current) { + initialize(scrollRef.current); + } + }, [initialize, scrollRef.current]); + + return ( +
+
+ {isOverflowing || showTitle ? title || children : ''} +
+
+ ); +}; + +export default React.memo(TitleTip); diff --git a/src/components/highlight-code/code-viewer.tsx b/src/components/highlight-code/code-viewer.tsx index 22843cc6..ec9d83cc 100644 --- a/src/components/highlight-code/code-viewer.tsx +++ b/src/components/highlight-code/code-viewer.tsx @@ -73,6 +73,7 @@ const CodeViewer: React.FC = (props) => { }} > = (props) => { updateScrollerPosition(0); }, 200); + const copyText = useMemo(() => { + if (!logs.length) { + return ''; + } + return logs?.map((item) => item.content).join('\n'); + }, [logs]); + useEffect(() => { createChunkConnection(); return () => { @@ -121,11 +128,7 @@ const LogsViewer: React.FC = (props) => { return (
- item.content).join('\n')} - type="text" - size="small" - > +
= ({ intl }) => { const currentVersion = getAtomStorage(GPUStackVersionAtom)?.version; const isProd = - currentVersion !== '0.0.0' && currentVersion.indexOf('rc') === -1; + currentVersion !== '0.0.0' && currentVersion?.indexOf('rc') === -1; const uiVersion = document.documentElement.getAttribute('data-version'); diff --git a/src/pages/dashboard/components/resource-utilization.tsx b/src/pages/dashboard/components/resource-utilization.tsx index 810546a3..006eb09a 100644 --- a/src/pages/dashboard/components/resource-utilization.tsx +++ b/src/pages/dashboard/components/resource-utilization.tsx @@ -5,11 +5,6 @@ import _ from 'lodash'; import { memo, useContext, useMemo } from 'react'; import { DashboardContext } from '../config/dashboard-context'; -const chartColorMap = { - tickLineColor: 'rgba(217,217,217,0.5)', - axislabelColor: 'rgba(0, 0, 0, 0.4)' -}; - const TypeKeyMap = { cpu: { label: 'CPU', diff --git a/src/pages/llmodels/components/model-card.tsx b/src/pages/llmodels/components/model-card.tsx index 0a006c82..888b9bf6 100644 --- a/src/pages/llmodels/components/model-card.tsx +++ b/src/pages/llmodels/components/model-card.tsx @@ -60,7 +60,7 @@ const ModelCard: React.FC<{ } }; - const removeMetadata = (str: string) => { + const removeMetadata = useCallback((str: string) => { let indexes = []; let index = str.indexOf('---'); @@ -75,7 +75,7 @@ const ModelCard: React.FC<{ return str.slice(indexes[1] + 3); } return str; - }; + }, []); // huggingface model card data const getHuggingfaceModelDetail = async () => { diff --git a/src/pages/playground/components/ground-left.tsx b/src/pages/playground/components/ground-left.tsx index bae28599..0d923dfb 100644 --- a/src/pages/playground/components/ground-left.tsx +++ b/src/pages/playground/components/ground-left.tsx @@ -10,6 +10,7 @@ import { memo, useEffect, useImperativeHandle, + useMemo, useRef, useState } from 'react'; @@ -51,7 +52,6 @@ const GroundLeft: React.FC = forwardRef((props, ref) => { const currentMessageRef = useRef(null); const paramsRef = useRef(null); const messageListLengthCache = useRef(0); - const [viewCodeMessage, setViewCodeMessage] = useState([]); const { initialize, updateScrollerPosition } = useOverlayScroller(); const { initialize: innitializeParams } = useOverlayScroller(); @@ -68,6 +68,13 @@ const GroundLeft: React.FC = forwardRef((props, ref) => { }; }); + const viewCodeMessage = useMemo(() => { + return generateMessages([ + { role: Roles.System, content: systemMessage }, + ...messageList + ]); + }, [messageList, systemMessage]); + const setMessageId = () => { messageId.current = messageId.current + 1; }; @@ -134,10 +141,6 @@ const GroundLeft: React.FC = forwardRef((props, ref) => { setMessageList((pre) => { return [...pre, ...currentMessageRef.current]; }); - console.log('messageList:', [ - ...messageList, - ...currentMessageRef.current - ]); const messageParams = [ { role: Roles.System, content: systemMessage }, @@ -147,8 +150,6 @@ const GroundLeft: React.FC = forwardRef((props, ref) => { const messages = generateMessages(messageParams); - setViewCodeMessage(messages); - const chatParams = { messages: messages, ...parameters, diff --git a/src/pages/playground/components/message-input.tsx b/src/pages/playground/components/message-input.tsx index 663a776d..0d189585 100644 --- a/src/pages/playground/components/message-input.tsx +++ b/src/pages/playground/components/message-input.tsx @@ -242,6 +242,7 @@ const MessageInput: React.FC = ({ const handleOnPaste = (e: any) => { e.preventDefault(); + const text = e.clipboardData.getData('text'); if (text) { const startPos = e.target.selectionStart; @@ -253,6 +254,11 @@ const MessageInput: React.FC = ({ text + message.content.slice(endPos) }); + if (endPos !== startPos) { + setTimeout(() => { + e.target.setSelectionRange(endPos, endPos); + }, 0); + } } else { getPasteContent(e); } diff --git a/src/pages/playground/components/multiple-chat/content-item.tsx b/src/pages/playground/components/multiple-chat/content-item.tsx index 9330b3fe..2ea0a3c9 100644 --- a/src/pages/playground/components/multiple-chat/content-item.tsx +++ b/src/pages/playground/components/multiple-chat/content-item.tsx @@ -116,6 +116,11 @@ const ContentItem: React.FC = ({ data.content.slice(0, startPos) + text + data.content.slice(endPos), uid: data.uid }); + if (endPos !== startPos) { + setTimeout(() => { + e.target.setSelectionRange(endPos, endPos); + }, 0); + } } else { getPasteContent(e); } diff --git a/src/pages/playground/components/multiple-chat/model-item.tsx b/src/pages/playground/components/multiple-chat/model-item.tsx index 80ce29d7..55fc42b4 100644 --- a/src/pages/playground/components/multiple-chat/model-item.tsx +++ b/src/pages/playground/components/multiple-chat/model-item.tsx @@ -67,10 +67,16 @@ const ModelItem: React.FC = forwardRef( const currentMessageRef = useRef([]); const modelScrollRef = useRef(null); const messageListLengthCache = useRef(0); - const [viewCodeMessage, setViewCodeMessage] = useState([]); const { initialize, updateScrollerPosition } = useOverlayScroller(); + const viewCodeMessage = useMemo(() => { + return generateMessages([ + { role: Roles.System, content: systemMessage }, + ...messageList + ]); + }, [messageList, systemMessage]); + const setMessageId = () => { messageId.current = messageId.current + 1; }; @@ -135,8 +141,6 @@ const ModelItem: React.FC = forwardRef( const messages = generateMessages(messageParams); - setViewCodeMessage(messages); - const chatParams = { messages: messages, ...params, @@ -362,14 +366,29 @@ const ModelItem: React.FC = forwardRef( options={modelFullList} onChange={handleModelChange} value={params.model} - optionRender={(data) => { + labelRender={(data) => { return ( + {data.label} + + ); + }} + optionRender={(data) => { + return ( + {data.label} diff --git a/src/pages/playground/components/view-code-modal.tsx b/src/pages/playground/components/view-code-modal.tsx index b909b653..2e4d5722 100644 --- a/src/pages/playground/components/view-code-modal.tsx +++ b/src/pages/playground/components/view-code-modal.tsx @@ -4,7 +4,7 @@ import { BulbOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Button, Modal } from 'antd'; import _ from 'lodash'; -import React, { useEffect, useState } from 'react'; +import React, { useMemo, useState } from 'react'; type ViewModalProps = { systemMessage?: string; @@ -33,14 +33,12 @@ const ViewCodeModal: React.FC = (props) => { title, open, onCancel, - systemMessage, messageList, parameters = {}, apiType = 'chat' } = props || {}; const intl = useIntl(); - const [codeValue, setCodeValue] = useState(''); const [lang, setLang] = useState(langMap.shell); const BaseURL = `${window.location.origin}/v1-openai`; @@ -49,40 +47,7 @@ const ViewCodeModal: React.FC = (props) => { const logcommand = apiType === 'chat' ? 'choices[0].message.content' : 'data[0].embedding'; - const generateCode = () => { - // const systemList = systemMessage - // ? [ - // { - // role: 'system', - // content: [ - // { - // type: 'text', - // text: systemMessage - // } - // ] - // } - // ] - // : []; - - // const formatMessageList = _.map(messageList, (item: any) => { - // return { - // role: item.role, - // content: [ - // { - // type: 'text', - // text: item.content - // }, - // ..._.map(item.imgs, (img: any) => { - // return { - // type: 'image_url', - // image_url: { - // url: img.dataUrl - // } - // }; - // }) - // ] - // }; - // }); + const codeValue = useMemo(() => { if (lang === langMap.shell) { const messages = messageList; const code = `curl ${window.location.origin}/v1-openai/${api} \\\n-H "Content-Type: application/json" \\\n-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\\n-d '${JSON.stringify( @@ -93,8 +58,9 @@ const ViewCodeModal: React.FC = (props) => { null, 2 )}'`; - setCodeValue(code); - } else if (lang === langMap.javascript) { + return code; + } + if (lang === langMap.javascript) { const messages = messageList; const code = `const OpenAI = require("openai");\n\nconst openai = new OpenAI({\n "apiKey": "YOUR_GPUSTACK_API_KEY",\n "baseURL": "${BaseURL}"\n});\n\nasync function main(){\n const params = ${JSON.stringify( { @@ -104,8 +70,10 @@ const ViewCodeModal: React.FC = (props) => { null, 4 )};\nconst response = await openai.${ClientType}.create(params);\n console.log(response.${logcommand});\n}\nmain();`; - setCodeValue(code); - } else if (lang === langMap.python) { + + return code; + } + if (lang === langMap.python) { const formattedParams = _.keys(parameters).reduce( (acc: string, key: string) => { if (parameters[key] === null) { @@ -124,9 +92,10 @@ const ViewCodeModal: React.FC = (props) => { ? `messages=${JSON.stringify(messageList, null, 2)}` : ''; const code = `from openai import OpenAI\n\nclient = OpenAI(\n base_url="${BaseURL}", \n api_key="YOUR_GPUSTACK_API_KEY"\n)\n\nresponse = client.${ClientType}.create(\n${formattedParams} ${messages})\nprint(response.${logcommand})`; - setCodeValue(code); + return code; } - }; + return ''; + }, [lang, messageList, parameters]); const handleOnChangeLang = (value: string) => { setLang(value); @@ -136,25 +105,6 @@ const ViewCodeModal: React.FC = (props) => { setLang(langMap.shell); onCancel(); }; - const editorConfig = { - minimap: { - enabled: false - }, - hover: { - enabled: false - }, - readOnly: true, - formatOnType: true, - formatOnPaste: true, - fontWeight: 'bold', - scrollbar: { - verticalSliderSize: 8 - } - }; - - useEffect(() => { - generateCode(); - }, [lang, messageList, parameters]); return ( <> @@ -228,4 +178,4 @@ const ViewCodeModal: React.FC = (props) => { ); }; -export default ViewCodeModal; +export default React.memo(ViewCodeModal);