فهرست منبع

Feat: add index bar to select tool panel of workflow (#6066)

Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
非法操作 9 ماه پیش
والد
کامیت
b29a36f461
4فایلهای تغییر یافته به همراه307 افزوده شده و 374 حذف شده
  1. 54 0
      web/app/components/workflow/block-selector/index-bar.tsx
  2. 20 4
      web/app/components/workflow/block-selector/tools.tsx
  3. 1 0
      web/package.json
  4. 232 370
      web/yarn.lock

+ 54 - 0
web/app/components/workflow/block-selector/index-bar.tsx

@@ -0,0 +1,54 @@
+import { pinyin } from 'pinyin-pro'
+
+export const groupItems = (items, getFirstChar) => {
+  const groups = items.reduce((acc, item) => {
+    const firstChar = getFirstChar(item)
+    if (!firstChar || firstChar.length === 0)
+      return acc
+
+    let letter
+
+    // transform Chinese to pinyin
+    if (/[\u4E00-\u9FA5]/.test(firstChar))
+      letter = pinyin(firstChar, { pattern: 'first', toneType: 'none' })[0].toUpperCase()
+    else
+      letter = firstChar.toUpperCase()
+
+    if (!/[A-Z]/.test(letter))
+      letter = '#'
+
+    if (!acc[letter])
+      acc[letter] = []
+
+    acc[letter].push(item)
+    return acc
+  }, {})
+
+  const letters = Object.keys(groups).sort()
+  // move '#' to the end
+  const hashIndex = letters.indexOf('#')
+  if (hashIndex !== -1) {
+    letters.splice(hashIndex, 1)
+    letters.push('#')
+  }
+  return { letters, groups }
+}
+
+const IndexBar = ({ letters, itemRefs }) => {
+  const handleIndexClick = (letter) => {
+    const element = itemRefs.current[letter]
+    if (element)
+      element.scrollIntoView({ behavior: 'smooth' })
+  }
+  return (
+    <div className="index-bar fixed right-4 top-36 flex flex-col items-center text-xs font-medium text-gray-500">
+      {letters.map(letter => (
+        <div className="hover:text-gray-900 cursor-pointer" key={letter} onClick={() => handleIndexClick(letter)}>
+          {letter}
+        </div>
+      ))}
+    </div>
+  )
+}
+
+export default IndexBar

+ 20 - 4
web/app/components/workflow/block-selector/tools.tsx

@@ -1,11 +1,13 @@
 import {
   memo,
   useCallback,
+  useRef,
 } from 'react'
 import { useTranslation } from 'react-i18next'
 import BlockIcon from '../block-icon'
 import { BlockEnum } from '../types'
 import type { ToolWithProvider } from '../types'
+import IndexBar, { groupItems } from './index-bar'
 import type { ToolDefaultValue } from './types'
 import Tooltip from '@/app/components/base/tooltip'
 import Empty from '@/app/components/tools/add-tool-modal/empty'
@@ -24,6 +26,9 @@ const Blocks = ({
   const { t } = useTranslation()
   const language = useGetLanguage()
 
+  const { letters, groups: groupedTools } = groupItems(tools, tool => tool.label[language][0])
+  const toolRefs = useRef({})
+
   const renderGroup = useCallback((toolWithProvider: ToolWithProvider) => {
     const list = toolWithProvider.tools
 
@@ -81,6 +86,18 @@ const Blocks = ({
     )
   }, [onSelect, language])
 
+  const renderLetterGroup = (letter) => {
+    const tools = groupedTools[letter]
+    return (
+      <div
+        key={letter}
+        ref={el => (toolRefs.current[letter] = el)}
+      >
+        {tools.map(renderGroup)}
+      </div>
+    )
+  }
+
   return (
     <div className='p-1 max-w-[320px] max-h-[464px] overflow-y-auto'>
       {
@@ -90,12 +107,11 @@ const Blocks = ({
       }
       {!tools.length && showWorkflowEmpty && (
         <div className='py-10'>
-          <Empty/>
+          <Empty />
         </div>
       )}
-      {
-        !!tools.length && tools.map(renderGroup)
-      }
+      {!!tools.length && letters.map(renderLetterGroup)}
+      {tools.length > 10 && <IndexBar letters={letters} itemRefs={toolRefs} />}
     </div>
   )
 }

+ 1 - 0
web/package.json

@@ -56,6 +56,7 @@
     "negotiator": "^0.6.3",
     "next": "^14.1.1",
     "next-nprogress-bar": "^2.3.8",
+    "pinyin-pro": "^3.23.0",
     "qrcode.react": "^3.1.0",
     "qs": "^6.11.1",
     "rc-textarea": "^1.5.2",

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 232 - 370
web/yarn.lock


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است