diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index bf4091e3..00000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/components/icon-font/iconfont/iconfont.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 555e77a0..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - extends: require.resolve('@umijs/max/eslint'), - rules: { - 'react/no-unstable-nested-components': 1, - 'no-unused-vars': 'off', - 'no-undef': 'error', - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/class-name-casing': 'off' - }, - globals: { - Global: 'readonly', - React: 'readonly', - JSX: 'readonly' - }, - ignorePatterns: ['public/static/'] -}; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..768677e4 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,77 @@ +import js from '@eslint/js'; +import prettier from 'eslint-config-prettier'; +import importPlugin from 'eslint-plugin-import'; +import reactPlugin from 'eslint-plugin-react'; +import reactHooks from 'eslint-plugin-react-hooks'; +import unusedImports from 'eslint-plugin-unused-imports'; +import { defineConfig, globalIgnores } from 'eslint/config'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; + +export default defineConfig([ + globalIgnores([ + 'public/static/', + 'dist', + 'src/.umi/', + 'src/.umi-production/', + 'src/.umi-test/' + ]), + { + files: ['**/*.{ts,tsx,js,jsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + prettier + ], + plugins: { + react: reactPlugin, + import: importPlugin, + 'unused-imports': unusedImports + }, + settings: { + react: { + version: 'detect' + }, + 'import/resolver': { + node: true, + typescript: true + } + }, + languageOptions: { + ecmaVersion: 2020, + globals: { + ...globals.browser, + ...globals.node, + Global: 'readonly', + React: 'readonly', + JSX: 'readonly' + } + }, + rules: { + 'react/no-unstable-nested-components': 'warn', + 'no-unused-vars': 'off', + 'no-undef': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-empty-object-type': 'off', + '@typescript-eslint/no-unnecessary-type-constraint': 'off', + 'unused-imports/no-unused-imports': 'error', + 'unused-imports/no-unused-vars': 'off', + 'import/no-unresolved': 'off', + 'react-hooks/exhaustive-deps': 'off', + 'react-hooks/preserve-manual-memoization': 'off', + 'react-hooks/set-state-in-effect': 'off', + 'react-hooks/refs': 'off', + 'react-hooks/use-memo': 'off', + 'react-hooks/immutability': 'off', + 'no-unsafe-optional-chaining': 'off', + 'no-empty': 'off', + 'no-constant-condition': 'off', + 'no-prototype-builtins': 'off', + 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0, maxBOF: 0 }] + } + } +]); diff --git a/package.json b/package.json index 6a4a9f3b..803af5d4 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@ant-design/icons": "^6.1.0", "@ant-design/pro-components": "3.1.0-0", "@braintree/sanitize-url": "^7.1.1", + "@gpustack/core-ui": "workspace:*", "@huggingface/gguf": "^0.1.7", "@huggingface/hub": "^0.15.1", "@huggingface/tasks": "^0.11.6", @@ -86,6 +87,7 @@ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" }, "devDependencies": { + "@eslint/js": "^9.39.4", "@types/node": "^25.0.3", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.0", @@ -96,8 +98,14 @@ "case-sensitive-paths-webpack-plugin": "^2.4.0", "compression-webpack-plugin": "^11.1.0", "css-loader": "^7.1.2", - "eslint": "^8.56.0", - "eslint-plugin-unused-imports": "^3.2.0", + "eslint": "^9.39.4", + "eslint-config-prettier": "^10.1.8", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-unused-imports": "^4.4.1", + "globals": "^17.4.0", "extract-css-loader": "^0.0.1", "file-loader": "^6.2.0", "husky": "^9.0.11", @@ -111,6 +119,7 @@ "prettier-plugin-two-style-order": "^1.0.1", "tsx": "^4.19.3", "typescript": "^5.4.5", + "typescript-eslint": "^8.58.0", "url-loader": "^4.1.1", "webpack-bundle-analyzer": "^4.10.2", "worker-loader": "^3.0.8" diff --git a/src/components/alert-info/block.tsx b/src/components/alert-info/block.tsx deleted file mode 100644 index e5c15584..00000000 --- a/src/components/alert-info/block.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { - CheckCircleFilled, - LoadingOutlined, - WarningFilled -} from '@ant-design/icons'; -import { Typography } from 'antd'; -import { createStyles } from 'antd-style'; -import classNames from 'classnames'; -import React from 'react'; -import styled from 'styled-components'; -import OverlayScroller, { OverlayScrollerOptions } from '../overlay-scroller'; -interface AlertInfoProps { - type: Global.MessageType; - message: React.ReactNode; - rows?: number; - icon?: React.ReactNode; - ellipsis?: boolean; - style?: React.CSSProperties; - contentStyle?: React.CSSProperties; - title?: React.ReactNode; - maxHeight?: number; - overlayScrollerProps?: OverlayScrollerOptions; -} - -const useStyles = createStyles(({ token, css }) => { - return { - alertBlockInfo: css` - padding-block: 6px; - padding-inline: 10px 16px; - position: relative; - padding-left: 32px; - text-align: left; - border-radius: ${token.borderRadiusLG}px; - margin: 0; - border: 1px solid transparent; - .ant-typography { - margin-bottom: 0; - } - - &.danger { - border-color: ${token.colorErrorBorder}; - background-color: ${token.colorErrorBg}; - } - - &.warning { - border-color: ${token.colorWarningBorder}; - background-color: ${token.colorWarningBg}; - } - - &.transition { - color: ${token.geekblue7}; - background: ${token.geekblue1}; - border-color: ${token.geekblue3}; - } - - &.success { - border: 1px solid ${token.colorSuccess}; - color: ${token.colorSuccessText}; - background: ${token.colorSuccessBg}; - - .content.success { - font-weight: var(--font-weight-normal); - } - } - .title { - position: absolute; - left: 0; - top: 0; - display: flex; - height: 32px; - padding: 5px 10px; - border-radius: ${token.borderRadius}px ${token.borderRadius}px 0 0; - - .info-icon { - &.danger { - color: ${token.colorErrorText}; - } - - &.warning { - color: ${token.colorWarningText}; - } - - &.transition { - color: ${token.geekblue7}; - } - - &.success { - color: ${token.colorSuccessText}; - } - } - - .text { - font-weight: var(--font-weight-bold); - } - } - ` - }; -}); - -const TitleWrapper = styled.div` - font-weight: 700; - color: var(--ant-color-text); -`; - -const ContentWrapper = styled.div<{ $hasTitle: boolean }>` - word-break: break-word; - color: ${(props) => - props.$hasTitle - ? 'var(--ant-color-text-secondary)' - : 'var(--ant-color-text)'}; - font-weight: var(--font-weight-500); - white-space: pre-line; -`; - -const AlertInfo: React.FC = (props) => { - const { - message, - type, - rows = 1, - ellipsis, - style, - title, - contentStyle, - icon, - maxHeight = 86, - overlayScrollerProps = {} - } = props; - const { styles } = useStyles(); - - const renderIcon = () => { - if (type === 'transition') { - return ; - } - if (type === 'success') { - return ; - } - return ; - }; - - return ( - <> - {message ? ( -
- -
- - {icon ?? renderIcon()} - -
- {title && ( - {title} - )} - - - {message} - - -
-
- ) : null} - - ); -}; - -export default AlertInfo; diff --git a/src/components/alert-info/index.tsx b/src/components/alert-info/index.tsx deleted file mode 100644 index 644a7a49..00000000 --- a/src/components/alert-info/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { WarningOutlined } from '@ant-design/icons'; -import { Typography } from 'antd'; -import React from 'react'; - -interface AlertInfoProps { - type: 'danger' | 'warning'; - message: string; - rows?: number; - icon?: React.ReactNode; - ellipsis?: boolean; - style?: React.CSSProperties; -} - -const AlertInfo: React.FC = (props) => { - const { message, type, rows = 1, ellipsis, style } = props; - - return ( - <> - {message ? ( - - - {message} - - ) : null} - - ); -}; - -export default AlertInfo; diff --git a/src/components/audio-animation/index.less b/src/components/audio-animation/index.less deleted file mode 100644 index d4828cd2..00000000 --- a/src/components/audio-animation/index.less +++ /dev/null @@ -1,19 +0,0 @@ -.canvas-wrap { - display: flex; - justify-content: center; - align-items: center; - text-align: center; - width: 100%; - - canvas { - display: block; - width: 100%; - image-rendering: crisp-edges; - } -} - -.scroller-wrapper { - width: 100%; - height: 100%; - overflow: hidden; -} diff --git a/src/components/audio-animation/index.tsx b/src/components/audio-animation/index.tsx deleted file mode 100644 index 2a297c68..00000000 --- a/src/components/audio-animation/index.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import useResizeObserver from '@/components/logs-viewer/use-size'; -import React, { useEffect, useState } from 'react'; -import './index.less'; - -interface AudioAnimationProps { - width: number; - height: number; - maxWidth?: number; - scaleFactor?: number; - maxBarCount?: number; - amplitude?: number; - fixedHeight?: boolean; - analyserData: { - data: Uint8Array; - analyser: any; - }; -} - -const AudioAnimation: React.FC = (props) => { - const { - scaleFactor = 1.2, - maxBarCount = 128, - amplitude = 40, - maxWidth, - fixedHeight = true, - analyserData, - width: initialWidth, - height: initialHeight - } = props; - const canvasRef = React.useRef(null); - const animationId = React.useRef(0); - const isScaled = React.useRef(false); - const oscillationOffset = React.useRef(0); - const direction = React.useRef(1); - const scrollerRef = React.useRef(null); - const [width, setWidth] = useState(initialWidth); - const [height, setHeight] = useState(initialHeight); - const containerRef = React.useRef(null); - - const size = useResizeObserver(scrollerRef); - - const calculateJitter = ( - i: number, - timestamp: number, - baseHeight: number, - minJitter: number, - jitterAmplitude: number - ) => { - // - const jitterFactor = Math.sin(timestamp / 200 + i) * 0.5 + 0.5; - const jitter = - minJitter + - jitterFactor * (jitterAmplitude - minJitter) * (baseHeight / maxBarCount); - return jitter; - }; - - const startAudioVisualization = () => { - if (!canvasRef.current || !analyserData.data?.length) return; - - const canvas = canvasRef.current; - const canvasCtx = canvas.getContext('2d'); - if (!canvasCtx) return; - - const WIDTH = (canvas.width = width * 2); - const HEIGHT = (canvas.height = height * 2); - - if (!isScaled.current) { - canvasCtx.scale(2, 2); - isScaled.current = true; - } - - const barWidth = 4; - const barSpacing = 6; - const centerLine = Math.floor(HEIGHT / 2); - - const jitterAmplitude = amplitude; - const minJitter = 10; - - let lastFrameTime = 0; - - const gradient = canvasCtx.createLinearGradient(0, 0, 0, HEIGHT); - gradient.addColorStop(0, '#007BFF'); - gradient.addColorStop(1, '#0069DA'); - canvasCtx.fillStyle = gradient; - - const draw = (timestamp: number) => { - const elapsed = timestamp - lastFrameTime; - if (elapsed < 16) { - animationId.current = requestAnimationFrame(draw); - return; - } - lastFrameTime = timestamp; - - analyserData.analyser?.current?.getByteFrequencyData(analyserData.data); - canvasCtx.clearRect(0, 0, WIDTH, HEIGHT); - - const barCount = Math.min(maxBarCount, analyserData.data.length); - const totalWidth = barCount * (barWidth + barSpacing) - barSpacing; - let x = WIDTH / 2 - totalWidth / 2 + oscillationOffset.current; - - oscillationOffset.current += direction.current; - if (Math.abs(oscillationOffset.current) > 20) { - direction.current *= -1; - } - - for (let i = 0; i < barCount; i++) { - const baseHeight = Math.floor(analyserData.data[i] / 2) * scaleFactor; - - const jitter = calculateJitter( - i, - timestamp, - baseHeight, - minJitter, - jitterAmplitude - ); - const barHeight = baseHeight + Math.round(jitter); - - const topY = Math.round(centerLine - barHeight / 2); - const bottomY = Math.round(centerLine + barHeight / 2); - - canvasCtx.beginPath(); - canvasCtx.moveTo(x, bottomY); - canvasCtx.lineTo(x, topY + 2); - canvasCtx.arcTo(x + barWidth, topY + 2, x + barWidth, bottomY, 2); - canvasCtx.lineTo(x + barWidth, bottomY); - canvasCtx.closePath(); - canvasCtx.fill(); - - x += barWidth + barSpacing; - } - - animationId.current = requestAnimationFrame(draw); - }; - - draw(performance.now()); - }; - - React.useEffect(() => { - if (size) { - if (maxWidth) { - setWidth(Math.min(size.width, maxWidth)); - } else { - setWidth(size?.width || 0); - } - if (!fixedHeight) { - setHeight(size?.height || 0); - } - } - }, [size, maxWidth]); - - useEffect(() => { - if (!canvasRef.current) return; - const clearCanvas = () => { - if (canvasRef.current) { - const ctx = canvasRef.current.getContext('2d'); - if (ctx) ctx.clearRect(0, 0, width * 2, height * 2); - } - }; - - if (!analyserData.data?.length || !analyserData.analyser?.current) { - clearCanvas(); - cancelAnimationFrame(animationId.current); - animationId.current = 0; - return; - } - - startAudioVisualization(); - - return () => { - cancelAnimationFrame(animationId.current); - clearCanvas(); - }; - }, [analyserData, width, height]); - - return ( -
-
- -
-
- ); -}; - -export default AudioAnimation; diff --git a/src/components/audio-player/audio-element.tsx b/src/components/audio-player/audio-element.tsx deleted file mode 100644 index 9601b9eb..00000000 --- a/src/components/audio-player/audio-element.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -const AudioWrapper = styled.div` - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: flex-start; -`; - -const AudioElement: React.FC = (props) => { - return ( -
- - - -
- ); -}; - -export default AudioElement; diff --git a/src/components/audio-player/config/type.ts b/src/components/audio-player/config/type.ts deleted file mode 100644 index 210fb88c..00000000 --- a/src/components/audio-player/config/type.ts +++ /dev/null @@ -1,39 +0,0 @@ -export type AudioEvent = - | 'play' - | 'playing' - | 'pause' - | 'timeupdate' - | 'ended' - | 'loadedmetadata' - | 'audioprocess' - | 'canplay' - | 'ended' - | 'loadeddata' - | 'seeked' - | 'seeking' - | 'volumechange'; - -export interface AudioPlayerProps { - controls?: boolean; - autoplay?: boolean; - url: string; - speed?: number; - ref?: any; - height?: number; - width?: number; - duration?: number; - onPlay?: () => void; - onPlaying?: () => void; - onPause?: () => void; - onTimeUpdate?: () => void; - onEnded?: () => void; - onLoadedMetadata?: (duration: number) => void; - onAudioProcess?: (current: number) => void; - onCanPlay?: () => void; - onLoadedData?: () => void; - onSeeked?: () => void; - onSeeking?: () => void; - onVolumeChange?: () => void; - onReady?: (duration: number) => void; - onAnalyse?: (analyseData: any, frequencyBinCount: any) => void; -} diff --git a/src/components/audio-player/index.less b/src/components/audio-player/index.less deleted file mode 100644 index 25668b32..00000000 --- a/src/components/audio-player/index.less +++ /dev/null @@ -1,103 +0,0 @@ -.player-wrap { - width: 100%; - display: flex; - // background-color: var(--ant-color-fill-quaternary); - border-radius: 6px; - - .player-ui { - padding: 8px 16px; - flex: 1; - display: flex; - justify-content: flex-start; - align-items: center; - } - - .controls { - width: 100%; - display: flex; - justify-content: space-between; - align-items: center; - } - - .play-btn { - margin-inline: 30px; - height: 22px; - width: 22px; - - .ant-btn { - height: 22px; - width: 22px; - } - } - - .backward, - .forward { - background: none !important; - } - - .slider { - display: flex; - justify-content: center; - align-items: center; - - .slider-inner { - flex: 1; - } - } - - .play-content { - display: flex; - justify-content: center; - align-items: center; - flex: 1; - } - - .time { - width: 52px; - text-align: right; - - &.current { - text-align: left; - } - } - - .progress-bar { - margin-inline: 10px; - flex: 1; - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: center; - - .slider { - width: 100%; - } - - .file-name { - margin-bottom: 6px; - line-height: 20px; - height: 20px; - display: flex; - align-items: center; - align-self: center; - justify-content: center; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } - - .ant-slider-horizontal { - margin-block: 5px; - } - } - - .speaker { - margin-left: 10px; - position: relative; - - .volume-slider { - position: absolute; - bottom: 30px; - } - } -} diff --git a/src/components/audio-player/index.tsx b/src/components/audio-player/index.tsx deleted file mode 100644 index ae315ff8..00000000 --- a/src/components/audio-player/index.tsx +++ /dev/null @@ -1,311 +0,0 @@ -import { formatTime } from '@/utils/index'; -import { - FastBackwardOutlined, - FastForwardOutlined, - PauseCircleFilled, - PlayCircleFilled -} from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Slider, Tooltip } from 'antd'; -import { round } from 'lodash'; -import React, { - forwardRef, - useCallback, - useEffect, - useImperativeHandle -} from 'react'; -import './index.less'; - -interface AudioPlayerProps { - autoplay?: boolean; - url: string; - speed?: number; - ref?: any; - name: string; - height?: number; - width?: number; - duration?: number; - extra?: React.ReactNode; -} - -const speedOptions = [ - { label: '1x', value: 1 }, - { label: '2x', value: 2 }, - { label: '3x', value: 3 }, - { label: '4x', value: 4 } -]; - -const speedConfig = { - min: 0.5, - max: 2, - step: 0.25 -}; - -const AudioPlayer: React.FC = forwardRef((props, ref) => { - const intl = useIntl(); - const { autoplay = false, speed: defaultSpeed = 1, extra } = props; - const audioRef = React.useRef(null); - const [audioState, setAudioState] = React.useState<{ - currentTime: number; - duration: number; - }>({ - currentTime: 0, - duration: 0 - }); - const [playOn, setPlayOn] = React.useState(false); - const [speakerOn, setSpeakerOn] = React.useState(false); - const [volume, setVolume] = React.useState(1); - const [speed, setSpeed] = React.useState(defaultSpeed); - const timer = React.useRef(null); - - useImperativeHandle(ref, () => ({ - play: () => { - audioRef.current?.play(); - }, - pause: () => { - audioRef.current?.pause(); - } - })); - const handleShowVolume = useCallback(() => { - setSpeakerOn(!speakerOn); - }, [speakerOn]); - - const handleSeepdChange = useCallback((value: number | string) => { - setSpeed(value as number); - audioRef.current!.playbackRate = value as number; - }, []); - - const handleAudioOnPlay = useCallback(() => { - console.log('audio play'); - timer.current = setInterval(() => { - setAudioState((prestate) => { - return { - currentTime: Math.ceil(audioRef.current?.currentTime || 0), - duration: - prestate.duration || Math.ceil(audioRef.current?.duration || 0) - }; - }); - - if (audioRef.current?.paused || audioRef.current?.ended) { - clearInterval(timer.current); - setPlayOn(false); - setAudioState((prestate: any) => { - return { - currentTime: audioRef.current?.ended ? 0 : prestate.currentTime, - duration: prestate.duration - }; - }); - } - }, 500); - }, []); - - const handlePlay = useCallback(() => { - setPlayOn(!playOn); - if (playOn) { - audioRef.current?.pause(); - } else { - audioRef.current?.play(); - } - }, [playOn]); - - const handleFormatVolume = (val?: number) => { - if (val === undefined) { - return `${round(volume * 100)}%`; - } - return `${round(val * 100)}%`; - }; - - const handleVolumeChange = useCallback((value: number) => { - audioRef.current!.volume = round(value, 2); - setVolume(round(value, 2)); - }, []); - - const initPlayerConfig = () => { - if (audioRef.current) { - audioRef.current!.volume = volume; - audioRef.current!.playbackRate = speed; - } - }; - - const handleLoadedMetadata = useCallback( - (data: any) => { - const duration = Math.ceil(audioRef.current?.duration || 0); - setAudioState({ - currentTime: 0, - duration: - duration && duration !== Infinity ? duration : props.duration || 0 - }); - setPlayOn(autoplay); - }, - [autoplay, props.duration] - ); - - const handleCurrentChange = useCallback((val: number) => { - audioRef.current!.currentTime = val; - setAudioState((prestate) => { - return { - currentTime: val, - duration: prestate.duration - }; - }); - }, []); - - const handleReduceSpeed = () => { - setSpeed((pre) => { - if (pre - speedConfig.step < speedConfig.min) { - return speedConfig.min; - } - const next = pre - speedConfig.step; - audioRef.current!.playbackRate = next; - return next; - }); - }; - - const handleAddSpeed = () => { - setSpeed((pre) => { - if (pre + speedConfig.step > speedConfig.max) { - return speedConfig.max; - } - const next = pre + speedConfig.step; - audioRef.current!.playbackRate = next; - return next; - }); - }; - - const handleOnLoad = (e: any) => { - console.log('onload', e); - }; - - const onDownload = useCallback(() => { - const url = props.url || ''; - const filename = props.name; - - const link = document.createElement('a'); - link.href = url; - link.download = filename; - document.body.appendChild(link); - link.click(); - link.remove(); - }, [props.url, props.name]); - - useEffect(() => { - if (audioRef.current) { - initPlayerConfig(); - } - }, [audioRef.current]); - - useEffect(() => { - return () => { - clearInterval(timer.current); - }; - }, []); - - return ( -
-
-
-
- {props.name} -
- {/* - {' '} - {formatTime(audioState.currentTime)} - */} -
- -
- {/* {formatTime(audioState.duration)} */} -
-
-
- - {' '} - {formatTime(audioState.currentTime)} - - - - - - - - - - - {formatTime(audioState.duration)} -
- {extra} -
-
-
-
- -
- ); -}); - -export default React.memo(AudioPlayer); diff --git a/src/components/audio-player/raw-audio-player.tsx b/src/components/audio-player/raw-audio-player.tsx deleted file mode 100644 index 69a1fa76..00000000 --- a/src/components/audio-player/raw-audio-player.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import React, { - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useRef -} from 'react'; -import { AudioPlayerProps } from './config/type'; - -const RawAudioPlayer: React.FC = forwardRef((props, ref) => { - const { autoplay = false } = props; - const audioRef = React.useRef(null); - - // =================== audio context ====================== - const audioContext = useRef(null); - const analyser = useRef(null); - const dataArray = useRef(null); - // ======================================================== - - const initAudioContext = useCallback(() => { - audioContext.current = new ( - window.AudioContext || (window as any).webkitAudioContext - )(); - - analyser.current = audioContext.current.createAnalyser(); - analyser.current.fftSize = 512; - dataArray.current = new Uint8Array(analyser.current.frequencyBinCount); - }, []); - - const generateVisualData = useCallback(() => { - const source = audioContext.current.createMediaElementSource( - audioRef.current - ); - source.connect(analyser.current); - analyser.current.connect(audioContext.current.destination); - }, []); - - const initEnvents = () => { - if (!audioRef.current) { - return; - } - - audioRef.current.addEventListener('complete', () => {}); - - audioRef.current.addEventListener('play', () => { - props.onAnalyse?.(dataArray.current, analyser); - props.onPlay?.(); - }); - - audioRef.current.addEventListener('pause', () => { - props.onAnalyse?.(dataArray.current, analyser); - props.onPause?.(); - }); - - audioRef.current.addEventListener('timeupdate', () => { - const current = audioRef.current?.currentTime || 0; - props.onTimeUpdate?.(); - props.onAudioProcess?.(current); - }); - - audioRef.current.addEventListener('ended', () => { - props.onEnded?.(); - }); - // add all other events - - audioRef.current.addEventListener('canplay', () => { - props.onCanPlay?.(); - }); - - audioRef.current.addEventListener('loadeddata', () => { - initEnvents(); - if (!audioContext.current) { - initAudioContext(); - generateVisualData(); - } - props.onLoadedData?.(); - }); - - audioRef.current.addEventListener('seeked', () => { - props.onSeeked?.(); - }); - - audioRef.current.addEventListener('seeking', () => { - props.onSeeking?.(); - }); - - audioRef.current.addEventListener('volumechange', () => { - props.onVolumeChange?.(); - }); - - audioRef.current.addEventListener('playing', () => { - props.onPlaying?.(); - }); - - audioRef.current.addEventListener('loadedmetadata', () => { - const duration = audioRef.current?.duration || 0; - props.onLoadedMetadata?.(duration); - props.onReady?.(duration); - }); - - audioRef.current.addEventListener('ended', () => { - props.onEnded?.(); - }); - - audioRef.current.addEventListener('loadeddata', () => { - props.onLoadedData?.(); - }); - }; - - useImperativeHandle(ref, () => ({ - play: () => { - if (audioRef.current) { - // If playback has ended, reset to beginning - if (audioRef.current.currentTime >= audioRef.current.duration) { - audioRef.current.currentTime = 0; - } - audioRef.current.play(); - } - }, - pause: () => { - audioRef.current?.pause(); - }, - seekTo: (ratio: number) => { - if (audioRef.current && audioRef.current.duration) { - audioRef.current.currentTime = ratio * audioRef.current.duration; - } - }, - // Compatibility layer for wavesurfer interface - wavesurfer: { - current: { - play: () => { - if (audioRef.current) { - // If playback has ended, reset to beginning - if (audioRef.current.currentTime >= audioRef.current.duration) { - audioRef.current.currentTime = 0; - } - return audioRef.current.play(); - } - return Promise.resolve(); - }, - isPlaying: () => { - return audioRef.current ? !audioRef.current?.paused : false; - } - } - } - })); - - useEffect(() => { - if (audioRef.current) { - initEnvents(); - } - return () => { - if (audioContext.current) { - audioContext.current.close(); - } - // remove all events - - audioRef.current?.removeEventListener('play', () => {}); - audioRef.current?.removeEventListener('pause', () => {}); - audioRef.current?.removeEventListener('timeupdate', () => {}); - audioRef.current?.removeEventListener('ended', () => {}); - audioRef.current?.removeEventListener('canplay', () => {}); - audioRef.current?.removeEventListener('loadeddata', () => {}); - audioRef.current?.removeEventListener('seeked', () => {}); - audioRef.current?.removeEventListener('seeking', () => {}); - audioRef.current?.removeEventListener('volumechange', () => {}); - audioRef.current?.removeEventListener('playing', () => {}); - audioRef.current?.removeEventListener('loadedmetadata', () => {}); - audioRef.current?.removeEventListener('ended', () => {}); - audioRef.current?.removeEventListener('loadeddata', () => {}); - }; - }, [audioRef.current]); - - // Reload audio when URL changes - useEffect(() => { - if (audioRef.current && props.url) { - audioRef.current.load(); - } - }, [props.url]); - - return ( - - ); -}); - -export default RawAudioPlayer; diff --git a/src/components/audio-player/simple-audio.tsx b/src/components/audio-player/simple-audio.tsx deleted file mode 100644 index 9016cc69..00000000 --- a/src/components/audio-player/simple-audio.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import { formatTime } from '@/utils/index'; -import { DeleteOutlined, DownloadOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Dropdown, Slider, type MenuProps } from 'antd'; -import { createStyles } from 'antd-style'; -import { round } from 'lodash'; -import React, { - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useMemo -} from 'react'; -import styled from 'styled-components'; -import AutoTooltip from '../auto-tooltip'; -import IconFont from '../icon-font'; - -type ActionItem = 'download' | 'delete' | 'speed'; - -interface AudioPlayerProps { - autoplay?: boolean; - url: string; - speed?: number; - ref?: any; - name: string; - height?: number; - width?: number; - duration?: number; - actions?: ActionItem[]; - onDelete?: () => void; -} - -const SliderWrapper = styled.div` - width: 100%; - display: flex; - align-items: center; - justify-content: flex-start; - gap: 8px; - .ant-slider { - flex: 1; - } - .time { - color: var(--ant-color-text-tertiary); - } -`; - -const useStyles = createStyles(({ css, token }) => { - // @ts-ignore - const isDarkMode = token.darkMode as boolean; - return { - wrapper: css` - position: relative; - min-width: 360px; - height: 54px; - display: flex; - align-items: center; - justify-content: flex-start; - padding: 8px 10px; - background-color: ${isDarkMode - ? 'var(--ant-color-fill-secondary)' - : '#F1F3F4'}; - border-radius: 28px; - .inner { - width: 100%; - display: flex; - align-items: center; - justify-content: flex-start; - flex: 1; - gap: 8px; - .slider { - display: flex; - flex-direction: column; - justify-content: center; - flex: 1; - .ant-slider { - margin: 0; - } - &:hover { - .ant-slider-handle { - opacity: 1; - transition: opacity 0.3s ease-in-out; - } - } - &:focus-within { - .ant-slider-handle { - opacity: 1; - } - } - } - - .ant-slider-handle { - opacity: 0; - &::before { - background-color: var(--ant-color-bg-spotlight); - border-radius: 50%; - } - &::after { - display: none; - } - } - } - ` - }; -}); - -const sliderStyles = { - rail: { - borderRadius: '4px', - backgroundColor: 'var(--ant-color-fill-secondary)' - }, - track: { - borderRadius: '4px', - backgroundColor: 'var(--ant-color-bg-spotlight)' - } -}; - -const speedOptions = [ - { label: '1x', value: 1 }, - { label: '2x', value: 2 }, - { label: '3x', value: 3 }, - { label: '4x', value: 4 } -]; - -const speedConfig = { - min: 0.5, - max: 2, - step: 0.25 -}; - -const AudioPlayer: React.FC = forwardRef((props, ref) => { - const intl = useIntl(); - const { styles } = useStyles(); - const { - autoplay = false, - speed: defaultSpeed = 1, - actions = ['delete'], - name, - onDelete - } = props; - const audioRef = React.useRef(null); - const [audioState, setAudioState] = React.useState<{ - currentTime: number; - duration: number; - }>({ - currentTime: 0, - duration: 0 - }); - console.log('audioState', name); - const [playOn, setPlayOn] = React.useState(false); - const [speakerOn, setSpeakerOn] = React.useState(false); - const [volume, setVolume] = React.useState(1); - const [speed, setSpeed] = React.useState(defaultSpeed); - const timer = React.useRef(null); - - useImperativeHandle(ref, () => ({ - play: () => { - audioRef.current?.play(); - }, - pause: () => { - audioRef.current?.pause(); - } - })); - const handleShowVolume = useCallback(() => { - setSpeakerOn(!speakerOn); - }, [speakerOn]); - - const handleSeepdChange = useCallback((value: number | string) => { - setSpeed(value as number); - audioRef.current!.playbackRate = value as number; - }, []); - - const handleAudioOnPlay = useCallback(() => { - timer.current = setInterval(() => { - setAudioState((prestate) => { - return { - currentTime: Math.ceil(audioRef.current?.currentTime || 0), - duration: - prestate.duration || Math.ceil(audioRef.current?.duration || 0) - }; - }); - - if (audioRef.current?.paused || audioRef.current?.ended) { - clearInterval(timer.current); - setPlayOn(false); - setAudioState((prestate: any) => { - return { - currentTime: audioRef.current?.ended ? 0 : prestate.currentTime, - duration: prestate.duration - }; - }); - } - }, 500); - }, []); - - const handlePlay = useCallback(() => { - setPlayOn(!playOn); - if (playOn) { - audioRef.current?.pause(); - } else { - audioRef.current?.play(); - } - }, [playOn]); - - const handleFormatVolume = (val?: number) => { - if (val === undefined) { - return `${round(volume * 100)}%`; - } - return `${round(val * 100)}%`; - }; - - const handleVolumeChange = useCallback((value: number) => { - audioRef.current!.volume = round(value, 2); - setVolume(round(value, 2)); - }, []); - - const initPlayerConfig = () => { - if (audioRef.current) { - audioRef.current!.volume = volume; - audioRef.current!.playbackRate = speed; - } - }; - - const handleLoadedMetadata = useCallback( - (data: any) => { - const duration = Math.ceil(audioRef.current?.duration || 0); - setAudioState({ - currentTime: 0, - duration: - duration && duration !== Infinity ? duration : props.duration || 0 - }); - setPlayOn(autoplay); - }, - [autoplay, props.duration] - ); - - const handleCurrentChange = useCallback((val: number) => { - audioRef.current!.currentTime = val; - setAudioState((prestate) => { - return { - currentTime: val, - duration: prestate.duration - }; - }); - }, []); - - const handleReduceSpeed = () => { - setSpeed((pre) => { - if (pre - speedConfig.step < speedConfig.min) { - return speedConfig.min; - } - const next = pre - speedConfig.step; - audioRef.current!.playbackRate = next; - return next; - }); - }; - - const handleAddSpeed = () => { - setSpeed((pre) => { - if (pre + speedConfig.step > speedConfig.max) { - return speedConfig.max; - } - const next = pre + speedConfig.step; - audioRef.current!.playbackRate = next; - return next; - }); - }; - - const handleOnLoad = (e: any) => { - console.log('onload', e); - }; - - const onDownload = useCallback(() => { - const url = props.url || ''; - const filename = props.name; - - const link = document.createElement('a'); - link.href = url; - link.download = filename || 'audio.mp3'; // Default filename - document.body.appendChild(link); - link.click(); - link.remove(); - }, [props.url, props.name]); - - const items: MenuProps['items'] = useMemo(() => { - return [ - { - key: 'download', - label: intl.formatMessage({ id: 'common.button.download' }), - icon: , - onClick: onDownload - }, - { - key: 'speed', - label: intl.formatMessage({ id: 'playground.params.speed' }), - icon: , - children: speedOptions.map((item) => ({ - key: item.value, - label: item.label, - onClick: () => handleSeepdChange(item.value) - })) - }, - { - key: 'delete', - label: intl.formatMessage({ id: 'common.button.delete' }), - icon: , - danger: true, - onClick: () => { - if (audioRef.current) { - audioRef.current.pause(); - audioRef.current.src = ''; - audioRef.current.load(); - } - setAudioState({ currentTime: 0, duration: 0 }); - setPlayOn(false); - onDelete?.(); - } - } - ].filter((item) => actions.includes(item.key as ActionItem)); - }, [actions, intl, onDownload, onDelete, handleSeepdChange]); - - useEffect(() => { - if (audioRef.current) { - initPlayerConfig(); - } - }, [audioRef.current]); - - useEffect(() => { - return () => { - clearInterval(timer.current); - }; - }, []); - - return ( -
-
- - -
-
- - {name} - -
- - {formatTime(audioState.currentTime)} - - -
- - - -
- -
- ); -}); - -export default React.memo(AudioPlayer); diff --git a/src/components/auto-image/index.less b/src/components/auto-image/index.less deleted file mode 100644 index 9298a78a..00000000 --- a/src/components/auto-image/index.less +++ /dev/null @@ -1,21 +0,0 @@ -.toolbar-wrapper { - padding: 0 24px; - color: rgba(255, 255, 255, 65%); - font-size: 16px; - background-color: rgba(0, 0, 0, 10%); - border-radius: 100px; -} - -.toolbar-wrapper .anticon { - padding: 12px; - cursor: pointer; -} - -.toolbar-wrapper .anticon[disabled] { - cursor: not-allowed; - opacity: 0.3; -} - -.toolbar-wrapper .anticon:hover { - opacity: 0.3; -} diff --git a/src/components/auto-image/index.tsx b/src/components/auto-image/index.tsx deleted file mode 100644 index 0ead6666..00000000 --- a/src/components/auto-image/index.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import fallbackImg from '@/assets/images/img_fallback.png'; -import { - DownloadOutlined, - EyeOutlined, - RotateLeftOutlined, - RotateRightOutlined, - SwapOutlined, - UndoOutlined, - ZoomInOutlined, - ZoomOutOutlined -} from '@ant-design/icons'; -import { Image as AntImage, ImageProps, Space } from 'antd'; -import { round } from 'lodash'; -import React, { useCallback, useEffect, useState } from 'react'; -import './index.less'; - -const AutoImage: React.FC< - ImageProps & { - height: number | string; - width?: number | string; - autoSize?: boolean; - preview?: boolean; - onLoad?: () => void; - } -> = (props) => { - const { height = 100, width: w, autoSize, preview = true, ...rest } = props; - const [width, setWidth] = useState(w || 0); - const [isError, setIsError] = useState(false); - - const getImgRatio = useCallback((url: string): Promise<{ ratio: number }> => { - return new Promise((resolve) => { - const img = new Image(); - img.onload = () => { - resolve({ ratio: round(img.width / img.height, 2) }); - }; - img.onerror = () => { - resolve({ ratio: 1 }); - }; - img.src = url; - }); - }, []); - - const handleOnLoad = useCallback(async () => { - if (autoSize) { - return; - } - const { ratio } = await getImgRatio(props.src || ''); - - if (typeof height === 'number') { - setWidth(height * ratio); - } else { - throw new Error('Height must be a number'); - } - }, [getImgRatio, height, props.src]); - - const onDownload = useCallback(() => { - const url = props.src || ''; - const filename = Date.now() + ''; - - const link = document.createElement('a'); - link.href = url; - link.download = filename; - document.body.appendChild(link); - link.click(); - link.remove(); - }, [props.src]); - - const handleImgLoad = useCallback(() => { - props.onLoad?.(); - setIsError(false); - }, [props.onLoad]); - - const handleOnError = useCallback((e: any) => { - setIsError(true); - e.target.src = fallbackImg; - }, []); - - useEffect(() => { - handleOnLoad(); - }, [handleOnLoad]); - - useEffect(() => { - setWidth(w || 0); - }, [w]); - - return ( - , - actionsRender: ( - _, - { - transform: { scale }, - actions: { - onFlipY, - onFlipX, - onRotateLeft, - onRotateRight, - onZoomOut, - onZoomIn, - onReset - } - } - ) => ( - - - - - - - - - - - ) - } - } - /> - ); -}; - -export default AutoImage; diff --git a/src/components/auto-image/progress-line.less b/src/components/auto-image/progress-line.less deleted file mode 100644 index 3e49983d..00000000 --- a/src/components/auto-image/progress-line.less +++ /dev/null @@ -1,44 +0,0 @@ -.img-wrapper { - position: relative; - display: inline-block; -} - -.img-wrapper .auto-image { - display: block; -} - -.img-wrapper .progress-wrapper { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; -} - -.progress-square { - width: 100%; - height: 100%; - transform: rotate(0deg); -} - -.progress-square-bg { - fill: none; -} - -.progress-square-fg { - fill: none; - stroke-linecap: square; - stroke-dasharray: 400; - stroke-dashoffset: 400; - transition: stroke-dashoffset 0.3s ease; -} - -.progress-text { - position: absolute; - color: black; - font-size: 20px; - font-weight: bold; -} diff --git a/src/components/auto-image/single-image.less b/src/components/auto-image/single-image.less deleted file mode 100644 index 28b32101..00000000 --- a/src/components/auto-image/single-image.less +++ /dev/null @@ -1,144 +0,0 @@ -.thumb-img { - position: relative; - display: flex; - max-width: 100%; - max-height: 100%; - justify-content: center; - align-items: center; - border-radius: var(--border-radius-base); - overflow: hidden; - - .label { - position: absolute; - top: 4px; - left: 4px; - height: 20px; - line-height: 20px; - border-radius: 12px; - padding: 0 8px; - background-color: var(--ant-geekblue-1); - z-index: 10; - transform: scale(0.9); - } - - .progress-wrapper { - position: absolute; - bottom: 20px; - left: 20px; - right: 20px; - } - - .small-progress-wrap { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - display: flex; - justify-content: center; - align-items: center; - background-color: rgba(0, 0, 0, 30%); - - .ant-progress-text { - color: var(--color-white-secondary); - } - } - - .img { - display: flex; - width: auto; - height: auto; - max-width: 100%; - max-height: 100%; - overflow: hidden; - border-radius: var(--border-radius-base); - cursor: pointer; - justify-content: center; - align-items: center; - } - - .del { - position: absolute; - top: 2px; - right: 2px; - font-size: var(--font-size-middle); - cursor: pointer; - background-color: var(--color-white-1); - display: none; - border-radius: 50%; - height: 16px; - width: 16px; - overflow: hidden; - pointer-events: all; - } - - &:hover { - .ant-image .ant-image-mask { - opacity: 1; - transition: opacity var(--ant-motion-duration-slow); - } - - .del { - display: flex; - justify-content: center; - align-items: center; - } - } -} - -.single-image { - // height: 100%; - width: inherit; - display: flex; - justify-content: center; - align-items: center; - overflow: hidden; - border-radius: var(--border-radius-base); - - &.loading { - width: 100%; - height: 100%; - } - - &.auto-bg-color { - position: relative; - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - filter: blur(100px); - backdrop-filter: blur(100px); - z-index: 5; - } - - .thumb-img { - position: relative; - z-index: 10; - border-radius: 0; - - .img { - border-radius: 0; - } - } - - .ant-image { - border-radius: 0; - } - - .mask { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - bottom: 0; - right: 0; - z-index: 1; - } - } -} diff --git a/src/components/auto-image/single-image.tsx b/src/components/auto-image/single-image.tsx deleted file mode 100644 index 8f763eba..00000000 --- a/src/components/auto-image/single-image.tsx +++ /dev/null @@ -1,209 +0,0 @@ -import { CloseCircleOutlined, LoadingOutlined } from '@ant-design/icons'; -import { Progress, ProgressProps, Spin } from 'antd'; -import classNames from 'classnames'; -import { round } from 'lodash'; -import ResizeObserver from 'rc-resize-observer'; -import React, { useCallback } from 'react'; -import AutoImage from './index'; -import './single-image.less'; -interface SingleImageProps { - loading?: boolean; - width?: number; - height?: number; - progress?: number; - maxHeight?: number; - maxWidth?: number; - dataUrl: string; - label?: React.ReactNode; - uid: number | string; - preview?: boolean; - autoSize?: boolean; - onDelete: (uid: number | string) => void; - onClick?: (item: any) => void; - autoBgColor?: boolean; - editable?: boolean; - style?: React.CSSProperties; - loadingSize?: ProgressProps['size']; - progressType?: 'line' | 'circle' | 'dashboard'; - progressColor?: string; - progressWidth?: number; -} - -const SingleImage: React.FC = (props) => { - const { - editable, - onDelete, - onClick, - autoSize, - uid, - loading, - width, - height, - progress, - maxHeight, - maxWidth, - dataUrl = '', - label, - style, - autoBgColor, - preview = true, - loadingSize = 'default' - } = props; - - const imgWrapper = React.useRef(null); - const [imgSize, setImgSize] = React.useState({ - width: width, - height: height - }); - - const thumImgWrapStyle = React.useMemo(() => { - return loading ? { width: '100%', height: '100%' } : {}; - }, [loading, imgSize]); - - const handleOnClick = useCallback(() => { - onClick?.(props); - }, [onClick, props]); - - const handleResize = useCallback( - (size: { width: number; height: number }) => { - if (!autoSize || !size.width || !size.height) return; - - const { width: containerWidth, height: containerHeight } = size; - const { width: originalWidth, height: originalHeight } = props; - - if (!originalWidth || !originalHeight) return; - - const widthRatio = containerWidth / originalWidth; - const heightRatio = containerHeight / originalHeight; - - const scale = Math.min(widthRatio, heightRatio, 1); - - const newWidth = originalWidth * scale; - const newHeight = originalHeight * scale; - - if (newWidth === imgSize.width && newHeight === imgSize.height) { - return; - } - setImgSize({ - width: newWidth, - height: newHeight - }); - }, - [autoSize, props.width, props.height] - ); - - const handleOnLoad = React.useCallback(async () => {}, []); - - const handleOnDelete = (uid: number | string, e: any) => { - e.stopPropagation(); - onDelete(uid); - }; - - const renderProgress = () => { - {round(progress, 0)}%} - railColor="var(--ant-color-fill-secondary)" - />; - }; - - return ( - -
- {autoBgColor && ( -
- )} - - <> - {label &&
{label}
} - {loading ? ( - - } - /> - - ) : ( - - - {progress && progress < 100 && ( - - ( - - {round(progress, 0)}% - - )} - strokeColor="var(--color-white-secondary)" - railColor="var(--ant-color-fill-secondary)" - /> - - )} - - )} - - - {editable && ( - handleOnDelete(uid, e)}> - - - )} -
-
-
- ); -}; - -export default SingleImage; diff --git a/src/components/auto-tooltip/index.tsx b/src/components/auto-tooltip/index.tsx deleted file mode 100644 index e7fae224..00000000 --- a/src/components/auto-tooltip/index.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { CloseOutlined } from '@ant-design/icons'; -import { Tag, Tooltip, type TagProps } from 'antd'; -import { throttle } from 'lodash'; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState -} from 'react'; -import styled from 'styled-components'; -import { TooltipOverlayScroller } from '../overlay-scroller'; - -// type TagProps = React.ComponentProps; - -interface AutoTooltipProps extends Omit { - children: React.ReactNode; - maxWidth?: number | string; - minWidth?: number | string; - color?: string; - style?: React.CSSProperties; - ghost?: boolean; - title?: React.ReactNode; - showTitle?: boolean; - closable?: boolean; - radius?: number | string; - filled?: boolean; - tooltipProps?: React.ComponentProps; -} - -const StyledTag = styled(Tag)` - margin: 0; - &.tag-filled { - border: none; - background-color: var(--ant-color-fill-secondary); - } -`; - -const AutoTooltip: React.FC = ({ - children, - maxWidth = '100%', - minWidth, - ghost = false, - title, - showTitle = false, - tooltipProps, - radius = 12, - filled = false, - ...tagProps -}) => { - const contentRef = useRef(null); - const [isOverflowing, setIsOverflowing] = useState(false); - const resizeObserver = useRef(null); - - const checkOverflow = useCallback(() => { - if (contentRef.current) { - const { scrollWidth, clientWidth } = contentRef.current; - setIsOverflowing(scrollWidth > clientWidth); - } - }, [contentRef.current]); - - useEffect(() => { - const element = contentRef.current; - if (!element) return; - resizeObserver.current?.disconnect(); - resizeObserver.current = new ResizeObserver(() => { - checkOverflow(); - }); - - resizeObserver.current?.observe(element); - - // Initial check - checkOverflow(); - - return () => { - resizeObserver.current?.disconnect(); - resizeObserver.current = null; - }; - }, [checkOverflow]); - - useEffect(() => { - const debouncedCheckOverflow = throttle(checkOverflow, 200); - window.addEventListener('resize', debouncedCheckOverflow); - return () => { - window.removeEventListener('resize', debouncedCheckOverflow); - debouncedCheckOverflow.cancel(); - }; - }, [checkOverflow]); - - useEffect(() => { - checkOverflow(); - }, [children, checkOverflow]); - - const tagStyle = useMemo( - () => ({ - maxWidth, - minWidth, - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap' as const, - ...tagProps.style - }), - [maxWidth, tagProps.style] - ); - - return ( - - {ghost ? ( -
- {children} -
- ) : ( - - ) : ( - false - ) - } - > - {children} - - )} -
- ); -}; - -export default AutoTooltip; diff --git a/src/components/auto-tooltip/title-tip.tsx b/src/components/auto-tooltip/title-tip.tsx deleted file mode 100644 index 71c38de4..00000000 --- a/src/components/auto-tooltip/title-tip.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { OverlayScroller } from '@/components/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; - - return ( - -
- {isOverflowing || showTitle ? title || children : ''} -
-
- ); -}; - -export default React.memo(TitleTip); diff --git a/src/components/bibtex-viewer/index.tsx b/src/components/bibtex-viewer/index.tsx deleted file mode 100644 index 372c955c..00000000 --- a/src/components/bibtex-viewer/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import bibtexParse from '@orcid/bibtex-parse-js'; -import { Typography } from 'antd'; -import React from 'react'; - -/* - @inproceedings{Lysenko:2010:GMC:1839778.1839781,\ - author = {Lysenko, Mikola and Nelaturi, Saigopal and Shapiro, Vadim},\ - title = {Group morphology with convolution algebras},\ - booktitle = {Proceedings of the 14th ACM Symposium on Solid and Physical Modeling},\ - series = {SPM '10},\ - year = {2010},\ - isbn = {978-1-60558-984-8},\ - location = {Haifa, Israel},\ - pages = {11--22},\ - numpages = {12},\ - url = {http://doi.acm.org/10.1145/1839778.1839781},\ - doi = {10.1145/1839778.1839781},\ - acmid = {1839781},\ - publisher = {ACM},\ - address = {New York, NY, USA},\ - } -*/ - -const BibTeXViewer: React.FC<{ data: string }> = ({ data }) => { - if (!data) { - return null; - } - const dataList = bibtexParse.toJSON(data); - return ( -
    - {dataList.map((item: any, index: number) => ( -
  1. - - {item.entryTags?.title}.{' '} - - {item.entryTags?.author}. - [{item.entryTags?.year}] - {item.entryTags?.journal && ( - .({item.entryTags?.journal}) - )} -
  2. - ))} -
- ); -}; - -export default BibTeXViewer; diff --git a/src/components/buttons/more.tsx b/src/components/buttons/more.tsx deleted file mode 100644 index c5847e8d..00000000 --- a/src/components/buttons/more.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { DoubleRightOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -interface MoreButtonProps { - show: boolean; - loadMore: () => void; - loading?: boolean; -} - -const MoreWrapper = styled.div` - display: flex; - justify-content: center; - margin-block: 16px; - opacity: 1; - transition: opacity 0.3s; - &.loading { - opacity: 0; - transition: opacity 0.3s ease-in-out; - } -`; - -const MoreButton: React.FC = (props) => { - const { show, loading, loadMore } = props; - const intl = useIntl(); - return ( - <> - {show ? ( - - - - ) : null} - - ); -}; - -export default MoreButton; diff --git a/src/components/card-wrapper/index.tsx b/src/components/card-wrapper/index.tsx deleted file mode 100644 index 95a0e7ed..00000000 --- a/src/components/card-wrapper/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - border-radius: var(--border-radius-lg); - background-color: var(--ant-color-bg-container); - box-shadow: none; - padding: 8px 16px; - border: 1px solid var(--ant-color-border); -`; - -const CardWrapper = (props: any) => { - const { children, style } = props; - return {children}; -}; - -export default CardWrapper; diff --git a/src/components/card-wrapper/simple-card.tsx b/src/components/card-wrapper/simple-card.tsx deleted file mode 100644 index d0d4214b..00000000 --- a/src/components/card-wrapper/simple-card.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { createStyles } from 'antd-style'; -import React from 'react'; -import styled from 'styled-components'; - -const SimpleCardItemWrapper = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; - height: 100%; - gap: 16px; -`; - -const useStyles = createStyles(({ css, token }) => ({ - wrapper: css` - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - background: ${token.colorBgContainer}; - border-radius: ${token.borderRadius}px; - padding: ${token.padding}px; - justify-content: center; - align-items: center; - gap: ${token.padding}px; - &.bordered { - border: 1px solid ${token.colorBorder}; - } - .title { - font-size: ${token.fontSize}px; - font-weight: var(--font-weight-medium); - } - .content { - display: flex; - justify-content: center; - align-items: center; - font-size: ${token.fontSize}px; - color: ${token.colorTextSecondary}; - gap: 8px; - .icon { - display: inline-block; - width: 10px; - height: 10px; - gap: 10px; - &.roundRect { - border-radius: 2px; - } - &.circle { - border-radius: 50%; - } - } - } - ` -})); -export const SimpleCardItem: React.FC<{ - title?: string; - content?: React.ReactNode; - style?: React.CSSProperties; - bordered?: boolean; - color?: string; - iconType?: string; -}> = (props) => { - const { styles, cx } = useStyles(); - - const { title, content, style, bordered, iconType, color } = props; - - return ( -
-
{title}
-
- {iconType && ( - - )} - {content} -
-
- ); -}; - -export const SimpleCard: React.FC<{ - dataList: { - label: string; - value: React.ReactNode; - color: string; - iconType?: string; - }[]; - height?: string | number; - bordered?: boolean; - styles?: { - wrapper?: React.CSSProperties; - item?: React.CSSProperties; - }; -}> = (props) => { - const { dataList, bordered, styles } = props; - - return ( - - {dataList.map((item, index) => ( - - ))} - - ); -}; diff --git a/src/components/check-buttons/index.tsx b/src/components/check-buttons/index.tsx deleted file mode 100644 index 559c872c..00000000 --- a/src/components/check-buttons/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Button } from 'antd'; -import React from 'react'; - -interface CheckButtonsProps { - options: Global.BaseOption[]; - onChange: (value: string | number) => void; - cancelable?: boolean; - size?: 'small' | 'middle' | 'large'; - type?: 'text' | 'primary' | 'default' | 'dashed' | 'link' | undefined; -} - -const CheckButtons: React.FC = (props) => { - const [type, setType] = React.useState(props.type || 'text'); - const [active, setActive] = React.useState(null); - const handleChange = (value: string | number) => { - props.onChange(value); - if (props.cancelable && active === value) { - setActive(null); - } else { - setActive(value); - } - }; - return ( -
- {props.options?.map?.((option, index) => { - return ( - - ); - })} -
- ); -}; - -export default React.memo(CheckButtons); diff --git a/src/components/collapse-container/headless-collapse.tsx b/src/components/collapse-container/headless-collapse.tsx deleted file mode 100644 index a41e644b..00000000 --- a/src/components/collapse-container/headless-collapse.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react'; - -interface CollapseProps { - open: boolean; - children: React.ReactNode; - duration?: number; - minHeight?: number; -} - -export default function Collapse({ - open, - children, - minHeight = 0, - duration = 200 -}: CollapseProps) { - const ref = useRef(null); - const [height, setHeight] = useState(minHeight); - - useEffect(() => { - const el = ref.current; - if (!el) return; - - if (open) { - const h = el.scrollHeight; - setHeight(h); - - const timer = setTimeout(() => { - setHeight('auto'); - }, duration); - - return () => clearTimeout(timer); - } else { - const h = el.scrollHeight; - setHeight(h); - - requestAnimationFrame(() => { - requestAnimationFrame(() => { - setHeight(0); - }); - }); - } - return undefined; - }, [open, duration]); - - return ( -
- {children} -
- ); -} diff --git a/src/components/collapse-container/index.tsx b/src/components/collapse-container/index.tsx deleted file mode 100644 index aa8aee47..00000000 --- a/src/components/collapse-container/index.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import IconFont from '@/components/icon-font'; -import { Card } from 'antd'; -import { createStyles } from 'antd-style'; -import classNames from 'classnames'; -import React, { useEffect, useRef, useState } from 'react'; -import styled from 'styled-components'; - -const CardStyled = styled(Card)` - box-shadow: none !important; - background-color: none; - &.isOpen { - .ant-card-head { - border-bottom: 1px solid var(--ant-color-border-secondary); - border-radius: var(--ant-border-radius) var(--ant-border-radius) 0 0; - } - } - .ant-card-head { - cursor: pointer; - background-color: var(--ant-color-fill-quaternary); - border-bottom: none; - border-radius: var(--ant-border-radius); - padding: 0 16px; - &:hover { - background-color: var(--ant-color-fill-secondary); - .del-btn { - display: block; - } - } - } - &.disabled { - .ant-card-head { - cursor: not-allowed; - background-color: var(--ant-color-fill-quaternary) !important; - } - } -`; - -const useStyles = createStyles(({ css, token }) => { - return { - title: css` - font-weight: 400; - min-height: 56px; - font-size: var(--font-size-base); - display: flex; - justify-content: space-between; - align-items: center; - cursor: pointer; - `, - expandIcon: css` - display: flex; - align-items: center; - gap: 8px; - `, - subtitle: css` - font-size: 14px; - color: ${token.colorTextSecondary}; - `, - content: css` - padding-top: 8px; - `, - left: css` - flex: 1; - `, - right: css` - display: flex; - align-items: center; - gap: 8px; - .del-btn { - display: none; - } - ` - }; -}); - -export interface CollapsibleContainerProps { - title?: React.ReactNode; - subtitle?: React.ReactNode; - right?: React.ReactNode; - deleteBtn?: React.ReactNode; - defaultOpen?: boolean; - open?: boolean; - collapsible?: boolean; - showExpandIcon?: boolean; - onToggle?: (open: boolean) => void; - disabled?: boolean; - variant?: 'outlined' | 'borderless' | undefined; - iconPlacement?: 'left' | 'right'; - className?: string; - children?: React.ReactNode; - styles?: { - root?: React.CSSProperties; - body?: React.CSSProperties; - header?: React.CSSProperties; - content?: React.CSSProperties; - }; -} - -export default function CollapsibleContainer({ - title, - subtitle, - right, - deleteBtn, - defaultOpen = true, - open, - onToggle, - disabled = false, - showExpandIcon = true, - variant = 'borderless', - className = '', - collapsible, - iconPlacement = 'left', - styles: cardStyles, - children -}: CollapsibleContainerProps) { - const { styles } = useStyles(); - const isControlled = typeof open === 'boolean'; - const [internalOpen, setInternalOpen] = useState(defaultOpen); - const isOpen = collapsible - ? isControlled - ? (open as boolean) - : internalOpen - : true; - - const toggle = () => { - if (disabled || !collapsible) return; - const next = !isOpen; - if (!isControlled) setInternalOpen(next); - onToggle?.(next); - }; - - const contentRef = useRef(null); - const [height, setHeight] = useState(isOpen ? 'auto' : '0px'); - - const renderIcon = () => { - if (showExpandIcon) { - return ( - - ); - } - return null; - }; - - const renderTitle = () => { - if (!collapsible) { - return null; - } - return ( -
-
-
- {iconPlacement === 'left' && renderIcon()} - {title &&
{title}
} -
- {subtitle &&
{subtitle}
} -
-
- {right && {right}} - {deleteBtn && {deleteBtn}} - {iconPlacement === 'right' && renderIcon()} -
-
- ); - }; - - useEffect(() => { - if (!collapsible) { - setHeight('auto'); - return; - } - if (isOpen) { - const scrollHeight = contentRef.current?.scrollHeight || 0; - setHeight(scrollHeight + 'px'); - const timer = setTimeout(() => setHeight('auto'), 200); - return () => clearTimeout(timer); - } else { - const scrollHeight = contentRef.current?.scrollHeight || 0; - setHeight(scrollHeight + 'px'); - requestAnimationFrame(() => setHeight('0px')); - return () => {}; - } - }, [isOpen, collapsible]); - - return ( - -
-
{children}
-
-
- ); -} diff --git a/src/components/content-wrapper/index.less b/src/components/content-wrapper/index.less deleted file mode 100644 index 47d6a555..00000000 --- a/src/components/content-wrapper/index.less +++ /dev/null @@ -1,17 +0,0 @@ -.content-wrapper { - .content { - padding-block-start: 0; - padding-block-end: 32px; - padding-inline: 40px; - } - - .title { - font-size: var(--font-size-large); - font-weight: 600; - line-height: 32px; - padding-block-start: 8px; - padding-block-end: 16px; - padding-inline-start: 40px; - padding-inline-end: 40px; - } -} diff --git a/src/components/content-wrapper/index.tsx b/src/components/content-wrapper/index.tsx deleted file mode 100644 index 8a210057..00000000 --- a/src/components/content-wrapper/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import './index.less'; - -const ContentWrapper: React.FC<{ - children: React.ReactNode; - title: React.ReactNode; - titleStyle?: React.CSSProperties; - contentStyle?: React.CSSProperties; -}> = ({ children, title = false, titleStyle, contentStyle }) => { - return ( -
- {title && ( -
- {title} -
- )} -
- {children} -
-
- ); -}; - -export default ContentWrapper; diff --git a/src/components/copy-button/index.tsx b/src/components/copy-button/index.tsx deleted file mode 100644 index 81062b1e..00000000 --- a/src/components/copy-button/index.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { CheckCircleFilled, CopyOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, message, Tooltip } from 'antd'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import AutoTooltip from '../auto-tooltip'; - -type CopyButtonProps = { - children?: React.ReactNode; - text: string; - fontSize?: string; - type?: 'text' | 'primary' | 'dashed' | 'link' | 'default'; - size?: 'small' | 'middle' | 'large'; - shape?: 'circle' | 'round' | 'default'; - tips?: string; - placement?: - | 'top' - | 'left' - | 'right' - | 'bottom' - | 'topLeft' - | 'topRight' - | 'bottomLeft' - | 'bottomRight'; - btnStyle?: React.CSSProperties; - style?: React.CSSProperties; -}; - -const CopyButton: React.FC = ({ - children, - tips, - text, - type = 'text', - shape = 'default', - fontSize = '14px', - style, - btnStyle, - placement, - size = 'small' -}) => { - const intl = useIntl(); - const [copied, setCopied] = useState(false); - const timerRef = useRef(); - - const resetCopied = () => { - window.clearTimeout(timerRef.current); - timerRef.current = window.setTimeout(() => { - setCopied(false); - }, 3000); - }; - - /** - * Modern clipboard API (works in secure contexts: HTTPS or localhost) - */ - const asyncCopy = async (value: string): Promise => { - try { - await navigator.clipboard.writeText(value); - return true; - } catch (error) { - return false; - } - }; - - /** - * Fallback: execCommand with copy event listener - * More reliable than textarea selection method - */ - const execCopy = (value: string): boolean => { - let copySuccess = false; - - const onCopy = (event: ClipboardEvent) => { - event.stopPropagation(); - event.preventDefault(); - event.clipboardData?.clearData(); - event.clipboardData?.setData('text/plain', value); - copySuccess = true; - }; - - try { - document.addEventListener('copy', onCopy, { capture: true }); - document.execCommand('copy'); - return copySuccess; - } catch (error) { - return false; - } finally { - document.removeEventListener('copy', onCopy, { capture: true }); - } - }; - - const handleCopy = async () => { - try { - // Try modern clipboard API first - if (await asyncCopy(text)) { - setCopied(true); - return; - } - - // Fallback to execCommand method - if (execCopy(text)) { - setCopied(true); - return; - } - - // Both methods failed - throw new Error('Copy failed'); - } catch (error) { - message.error(intl.formatMessage({ id: 'common.copy.fail' }) as string); - } - }; - - const tipTitle = useMemo(() => { - if (copied) { - return intl.formatMessage({ id: 'common.button.copied' }); - } - return tips ?? intl.formatMessage({ id: 'common.button.copy' }); - }, [copied, tips, intl]); - - useEffect(() => { - resetCopied(); - }, [copied]); - - return ( -
- {children && ( - - {children} - - )} - - - - - -
- ); -}; - -export default CopyButton; diff --git a/src/components/delete-modal/index.tsx b/src/components/delete-modal/index.tsx deleted file mode 100644 index 690723e7..00000000 --- a/src/components/delete-modal/index.tsx +++ /dev/null @@ -1,224 +0,0 @@ -import useBodyScroll from '@/hooks/use-body-scroll'; -import { ExclamationCircleFilled } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { - Button, - Checkbox, - Modal, - Space, - message, - type ModalFuncProps -} from 'antd'; -import { createStyles } from 'antd-style'; -import { forwardRef, useImperativeHandle, useState } from 'react'; -import styled from 'styled-components'; - -const useStyles = createStyles(({ css }) => ({ - 'delete-modal-content': css` - display: flex; - font-size: var(--font-size-middle); - .anticon { - font-size: 20px; - margin-right: 10px; - color: var(--ant-color-warning); - } - .title { - display: flex; - align-items: center; - font-weight: var(--font-weight-500); - } - `, - content: css` - padding-top: 15px; - padding-left: 30px; - color: var(--ant-color-text-secondary); - white-space: pre-line; - word-break: break-all; - span { - color: var(--ant-color-text); - display: flex; - margin-top: 8px; - } - ` -})); - -const CheckboxWrapper = styled.div` - margin-top: 20px; - margin-left: 30px; - display: flex; - justify-content: flex-start; - align-items: center; - .check-text { - font-weight: 700; - color: var(--ant-color-warning); - } -`; - -interface DataOptions { - content?: string; - selection?: boolean; - name?: string; - okText?: string; - cancelText?: string; - title?: string; - operation: string; - checkConfig?: { - checkText: string; - defautlChecked: boolean; - }; -} - -interface Configuration { - checked: boolean; -} - -// default need to pass content and operation -const DeleteModal = forwardRef((props, ref) => { - const intl = useIntl(); - const { styles } = useStyles(); - const { saveScrollHeight, restoreScrollHeight } = useBodyScroll(); - const [visible, setVisible] = useState(false); - const [configuration, setConfiguration] = useState({ - checked: false - }); - const [delLoading, setDelLoading] = useState(false); - const [config, setConfig] = useState({} as any); - - const show = (data: ModalFuncProps & DataOptions) => { - saveScrollHeight(); - setConfig(data); - setConfiguration({ - checked: data.checkConfig?.defautlChecked || false - }); - setVisible(true); - }; - - const hide = () => { - setVisible(false); - restoreScrollHeight(); - }; - - const handleCancel = () => { - setVisible(false); - config.onCancel?.(); - restoreScrollHeight(); - }; - - const handleOk = async () => { - try { - setDelLoading(true); - const res = await config.onOk?.(); - const isArray = Array.isArray(res); - if (isArray) { - const allSuccess = res.every( - (item: any) => item?.status === 'fulfilled' - ); - if (allSuccess) { - message.success(intl.formatMessage({ id: 'common.message.success' })); - } - } else { - message.success(intl.formatMessage({ id: 'common.message.success' })); - } - } catch (error) { - // Handle error if needed - } finally { - setVisible(false); - setDelLoading(false); - restoreScrollHeight(); - } - }; - - useImperativeHandle(ref, () => ({ - show, - hide, - configuration - })); - - return ( - - - - - } - > -
- - - - {config.title - ? intl.formatMessage({ id: config.title }) - : intl.formatMessage({ id: 'common.title.delete.confirm' })} - - -
-
- {config.checkConfig && ( - - - setConfiguration({ - checked: e.target.checked - }) - } - > - - {intl.formatMessage({ id: config.checkConfig?.checkText })} - - - - )} -
- ); -}); - -export default DeleteModal; diff --git a/src/components/divider-line/index.less b/src/components/divider-line/index.less deleted file mode 100644 index dde6eafa..00000000 --- a/src/components/divider-line/index.less +++ /dev/null @@ -1,20 +0,0 @@ -.divider-line { - height: 8px; - // border-radius: 4px; - width: 100%; - // background-color: var(--color-fill-1); - z-index: 100; - margin: 0; - position: relative; - &::after { - content: ''; - position: absolute; - top: 0; - left: -9px; - bottom: 0; - right: 0; - height: 100%; - background: var(--color-fill-1); - // border-radius: 4px; - } -} diff --git a/src/components/divider-line/index.tsx b/src/components/divider-line/index.tsx deleted file mode 100644 index c15be85a..00000000 --- a/src/components/divider-line/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import styles from './index.less'; -const DividerLine: React.FC = () => { - return
; -}; - -export default DividerLine; diff --git a/src/components/drop-down-actions/index.tsx b/src/components/drop-down-actions/index.tsx deleted file mode 100644 index 68b35f64..00000000 --- a/src/components/drop-down-actions/index.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { useIntl } from '@umijs/max'; -import { Dropdown, DropDownProps } from 'antd'; -import _ from 'lodash'; -import React, { useMemo } from 'react'; - -const DropDownActions: React.FC = (props) => { - const { - menu, - trigger = ['hover'], - placement = 'bottomRight', - children, - ...rest - } = props; - const intl = useIntl(); - - const items = useMemo(() => { - return menu?.items?.map((item: any) => ({ - ..._.omit(item, 'locale'), - icon: item.icon - ? React.cloneElement(item.icon, { style: { fontSize: 14 } }) - : null, - label: item.locale ? intl.formatMessage({ id: item.label }) : item.label - })); - }, [menu?.items, intl]); - return ( - - {children} - - ); -}; - -export default DropDownActions; diff --git a/src/components/drop-down-buttons/index.less b/src/components/drop-down-buttons/index.less deleted file mode 100644 index fdefa3d3..00000000 --- a/src/components/drop-down-buttons/index.less +++ /dev/null @@ -1,4 +0,0 @@ -.dropdown-button.middle { - height: 28px; - width: 28px; -} diff --git a/src/components/drop-down-buttons/index.tsx b/src/components/drop-down-buttons/index.tsx deleted file mode 100644 index 8cf7af7b..00000000 --- a/src/components/drop-down-buttons/index.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { MoreOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Dropdown, Space, Tooltip, type MenuProps } from 'antd'; -import classNames from 'classnames'; -import _ from 'lodash'; -import React from 'react'; -import styled from 'styled-components'; -import './index.less'; - -type Trigger = 'click' | 'hover'; -interface DropdownButtonsProps { - items: MenuProps['items']; - size?: 'small' | 'middle' | 'large'; - trigger?: Trigger[]; - showText?: boolean; - disabled?: boolean; - variant?: 'filled' | 'outlined'; - color?: string; - extra?: React.ReactNode; - onSelect: (val: any, item?: any) => void; -} - -const DropdownWrapper = styled.div` - display: flex; - flex-direction: column; - background-color: var(--ant-color-bg-elevated); - padding: 5px; - align-items: flex-start; - border-radius: var(--border-radius-base); - box-shadow: var(--ant-box-shadow-secondary); - min-width: 160px; -`; - -const DropdownButtons: React.FC< - DropdownButtonsProps & { items: MenuProps['items'] } -> = ({ - items, - size = 'middle', - trigger = ['hover'], - showText, - disabled, - variant, - color, - extra, - onSelect -}) => { - const headItem = _.head(items); - const intl = useIntl(); - - const handleMenuClick = (item: any) => { - const selectItem = _.find(items, { key: item.key }); - onSelect(item.key, selectItem); - }; - - const handleButtonClick = (e: any) => { - const headItem = _.head(items); - onSelect(headItem.key, headItem); - }; - - if (!items?.length) { - return ; - } - - return ( - <> - {items?.length === 1 ? ( - - - - ) : ( - - <> - {showText ? ( - - ) : ( - - - - )} - - ({ - ..._.omit(item, ['label', 'locale']), - ...item.props, - label: - item.locale || item.locale === undefined - ? intl.formatMessage({ id: item.label }) - : item.label - })) - }} - > - - - - )} - - ); -}; - -export default DropdownButtons; diff --git a/src/components/dynamic-form/components/field-item.tsx b/src/components/dynamic-form/components/field-item.tsx deleted file mode 100644 index 24966ab4..00000000 --- a/src/components/dynamic-form/components/field-item.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import ComponentsMap from '@/components/seal-form/config/components'; -import { SealFormItemProps } from '@/components/seal-form/types'; -import { Form } from 'antd'; -import React from 'react'; - -interface FieldItemProps extends SealFormItemProps { - widget: keyof typeof ComponentsMap; - name: string; -} - -const FieldItem: React.FC = (props) => { - const { name, widget, required = [], ...rest } = props; - - const Component = ComponentsMap[widget]; - - return ; -}; - -export default FieldItem; diff --git a/src/components/dynamic-form/components/form-widget.tsx b/src/components/dynamic-form/components/form-widget.tsx deleted file mode 100644 index d741dfa2..00000000 --- a/src/components/dynamic-form/components/form-widget.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import ComponentsMap from '@/components/seal-form/config/components'; -import { FormWidgetProps } from '../config/types'; - -const FormWidget: React.FC< - FormWidgetProps & { - onChange?: (data: any) => void; - disabled?: boolean; - } -> = ({ - widget, - title: label, - required, - placeholder, - options, - description, - enum: enumValues, - style, - value, - min, - max, - status, - checked, - isInFormItems, - disabled, - onChange -}) => { - const Component = ComponentsMap[widget]; - - const optionList = enumValues?.map((item: string | number) => ({ - label: item, - value: item - })); - - return Component ? ( - - ) : null; -}; - -export default FormWidget; diff --git a/src/components/dynamic-form/components/list-map.tsx b/src/components/dynamic-form/components/list-map.tsx deleted file mode 100644 index 93785bd5..00000000 --- a/src/components/dynamic-form/components/list-map.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import Wrapper from '@/components/label-selector/wrapper'; -import { MinusOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React, { useEffect, useMemo } from 'react'; -import styled from 'styled-components'; -import { statusType } from '../config/types'; -import FormWidget from './form-widget'; - -const RowWrapper = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 8px; -`; - -const WidgetBox = styled.div` - display: flex; - align-items: center; - gap: 8px; - width: 100%; -`; -interface ListMapProps { - minItems?: number; - dataList: any[]; - label?: React.ReactNode; - btnText?: string; - requiredFields?: string[]; - validateStatusList?: Record[]; - properties: Record; - disabled?: boolean; - onAdd?: (data: any[]) => void; - onDelete?: (deletedItem: any, data: any[]) => void; - onChange?: (data: any) => void; -} - -interface ListItemProps { - schemaList: any[]; - data: Record; - disabled?: boolean; - validateStatus?: Record; - onChange?: (data: any) => void; -} - -const ListItem: React.FC = ({ - schemaList, - data, - onChange, - validateStatus, - disabled -}) => { - const handleValueChange = (name: string, target: any) => { - if (target?.target?.type === 'checkbox') { - const checked = target.target?.checked; - onChange?.({ [name]: checked }); - } else { - const value = target?.target ? target.target.value : target; - onChange?.({ [name]: value }); - } - }; - return ( - <> - {schemaList.map((schema: any) => ( - handleValueChange(schema.name, target)} - /> - ))} - - ); -}; - -const ListMap: React.FC = ({ - dataList = [], - label, - btnText, - properties = {}, - requiredFields = [], - minItems = 0, - validateStatusList = [], - disabled, - onAdd, - onDelete, - onChange -}) => { - const [items, setItems] = React.useState(dataList || []); - - const schemaList = useMemo(() => { - const list = Object.entries(properties).map(([key, value]) => ({ - ...value, - required: requiredFields.includes(key), - name: key - })); - return list; - }, [properties, requiredFields]); - - const handleOnAdd = () => { - const keys = Object.keys(properties); - const newItems = [ - ...items, - { ...keys.reduce((acc, key) => ({ ...acc, [key]: '' }), {}) } - ]; - setItems(newItems); - onAdd?.(newItems); - }; - - const handleDelete = (index: number) => { - const deleteItem = items[index]; - const newItems = items.filter((_, i) => i !== index); - setItems(newItems); - onDelete?.(deleteItem, newItems); - }; - - const handleItemChange = (index: number, data: { [key: string]: any }) => { - const newItems = [...items]; - newItems[index] = { ...newItems[index], ...data }; - setItems(newItems); - onChange?.(newItems); - }; - - useEffect(() => { - if (!dataList.length && minItems > 0) { - handleOnAdd(); - } - }, []); - - useEffect(() => { - setItems(dataList); - }, [dataList]); - - return ( - - {items.map((item, index) => ( - - - handleItemChange(index, value)} - /> - - {!disabled && ( - - )} - {showCancel && ( - - )} - - ); -}; - -export default FormButtons; diff --git a/src/components/highlight-code/code-viewer-dark.tsx b/src/components/highlight-code/code-viewer-dark.tsx deleted file mode 100644 index 1d5b8bb0..00000000 --- a/src/components/highlight-code/code-viewer-dark.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import CodeViewer from './code-viewer'; -import './styles/dark.less'; - -interface CodeViewerProps { - code: string; - copyValue?: string; - lang: string; - autodetect?: boolean; - ignoreIllegals?: boolean; - copyable?: boolean; - height?: string | number; - style?: React.CSSProperties; - xScrollable?: boolean; -} -const DarkViewer: React.FC = (props) => { - const { - code, - copyValue, - lang, - autodetect, - ignoreIllegals, - copyable, - height = 'auto', - xScrollable = false - } = props || {}; - - return ( - - ); -}; - -export default DarkViewer; diff --git a/src/components/highlight-code/code-viewer-light.tsx b/src/components/highlight-code/code-viewer-light.tsx deleted file mode 100644 index 7de78b8e..00000000 --- a/src/components/highlight-code/code-viewer-light.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import CodeViewer from './code-viewer'; -import './styles/light.less'; - -interface CodeViewerProps { - code: string; - copyValue?: string; - lang: string; - autodetect?: boolean; - ignoreIllegals?: boolean; - copyable?: boolean; - height?: string | number; - style?: React.CSSProperties; - xScrollable?: boolean; -} -const LightViewer: React.FC = (props) => { - const { - code, - copyValue, - lang, - autodetect, - ignoreIllegals, - copyable, - style, - height = 'auto', - xScrollable = false - } = props || {}; - - return ( - - ); -}; - -export default LightViewer; diff --git a/src/components/highlight-code/code-viewer.tsx b/src/components/highlight-code/code-viewer.tsx deleted file mode 100644 index 8aa5ec18..00000000 --- a/src/components/highlight-code/code-viewer.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import classNames from 'classnames'; -import hljs from 'highlight.js'; -import { useMemo } from 'react'; -import styled from 'styled-components'; -import CopyButton from '../copy-button'; -import { escapeHtml } from './utils'; - -interface CodeViewerProps { - code: string; - copyValue?: string; - lang: string; - autodetect?: boolean; - ignoreIllegals?: boolean; - copyable?: boolean; - height?: string | number; - theme?: 'light' | 'dark'; - style?: React.CSSProperties; - xScrollable?: boolean; -} - -interface CodeHeaderProps { - copyValue: string; - copyable: boolean; - lang: string; - theme: 'light' | 'dark'; -} - -const CodeHeaderWrapper = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - height: 32px; - padding: 0 12px; - font-size: 12px; - color: var(--ant-color-text-tertiary); - background-color: #fafafa; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - &.dark { - background-color: var(--color-editor-header-bg); - color: rgba(255, 255, 255, 0.65); - } -`; - -const Wrapper = styled.div` - border-radius: var(--border-radius-mini); - &:hover { - .custome-scrollbar { - &::-webkit-scrollbar-thumb { - background-color: var(--color-scrollbar-thumb); - border-radius: 4px; - } - } - } -`; - -const CodeHeader: React.FC = ({ - copyValue, - lang, - theme, - copyable -}) => { - if (!copyable) { - return null; - } - return ( - - {lang} - - - ); -}; - -const CodeViewer: React.FC = (props) => { - const { - code = '', - copyValue, - lang, - autodetect = true, - ignoreIllegals = true, - copyable = true, - height = 'auto', - style, - xScrollable = false - } = props || {}; - - const highlightedCode = useMemo(() => { - const autodetectLang = autodetect && !lang; - const cannotDetectLanguage = !autodetectLang && !hljs.getLanguage(lang); - let className = ''; - - if (!cannotDetectLanguage) { - className = `hljs ${lang}`; - } - - // No idea what language to use, return raw code - if (cannotDetectLanguage) { - console.warn(`The language "${lang}" you specified could not be found.`); - return { - value: escapeHtml(code), - className: className - }; - } - - if (autodetectLang) { - const result = hljs.highlightAuto(code); - return { - value: result.value, - className: className - }; - } - const result = hljs.highlight(code, { - language: lang, - ignoreIllegals: ignoreIllegals - }); - return { - value: result.value, - className: className - }; - }, [code, lang, autodetect, ignoreIllegals]); - - return ( - - -
-        
-      
-
- ); -}; - -export default CodeViewer; diff --git a/src/components/highlight-code/index.tsx b/src/components/highlight-code/index.tsx deleted file mode 100644 index c731f63e..00000000 --- a/src/components/highlight-code/index.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import useUserSettings from '@/hooks/use-user-settings'; -import React from 'react'; -import CodeViewerDark from './code-viewer-dark'; -import CodeViewerLight from './code-viewer-light'; -import './styles/index.less'; - -const HighlightCode: React.FC<{ - code: string; - lang?: string; - copyable?: boolean; - theme?: 'light' | 'dark'; - fixedTheme?: 'light' | 'dark'; - xScrollable?: boolean; - height?: string | number; - style?: React.CSSProperties; - copyValue?: string; -}> = (props) => { - const { - style, - code, - copyValue, - lang = 'bash', - copyable = true, - theme, - height = 'auto', - xScrollable = false - } = props; - - const { userSettings } = useUserSettings(); - - const currentTheme = React.useMemo(() => { - const res = theme || userSettings.theme === 'realDark' ? 'dark' : 'light'; - return res; - }, [theme, userSettings.theme]); - - return ( -
- {currentTheme === 'dark' ? ( - - ) : ( - - )} -
- ); -}; - -export default HighlightCode; diff --git a/src/components/highlight-code/styles/dark.less b/src/components/highlight-code/styles/dark.less deleted file mode 100644 index dae651b5..00000000 --- a/src/components/highlight-code/styles/dark.less +++ /dev/null @@ -1,106 +0,0 @@ -// @ts-ingore -pre code.hljs { - display: block; - overflow-x: auto; - padding: 1em; -} - -code.hljs { - padding: 3px 5px; -} - -/* - -Atom One Dark by Daniel Gamage -Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax - -base: #282c34 -mono-1: #abb2bf -mono-2: #818896 -mono-3: #5c6370 -hue-1: #56b6c2 -hue-2: #61aeee -hue-3: #c678dd -hue-4: #98c379 -hue-5: #e06c75 -hue-5-2: #be5046 -hue-6: #d19a66 -hue-6-2: #e6c07b - -*/ -.code-pre.dark { - .hljs { - color: #abb2bf; - background: var(--color-editor-dark); - } - - .hljs-comment, - .hljs-quote { - color: #5c6370; - font-style: italic; - } - - .hljs-doctag, - .hljs-keyword, - .hljs-formula { - color: #c678dd; - } - - .hljs-section, - .hljs-name, - .hljs-selector-tag, - .hljs-deletion, - .hljs-subst { - color: #e06c75; - } - - .hljs-literal { - color: #56b6c2; - } - - .hljs-string, - .hljs-regexp, - .hljs-addition, - .hljs-attribute, - .hljs-meta .hljs-string { - color: #98c379; - } - - .hljs-attr, - .hljs-variable, - .hljs-template-variable, - .hljs-type, - .hljs-selector-class, - .hljs-selector-attr, - .hljs-selector-pseudo, - .hljs-number { - color: #d19a66; - } - - .hljs-symbol, - .hljs-bullet, - .hljs-link, - .hljs-meta, - .hljs-selector-id, - .hljs-title { - color: #61aeee; - } - - .hljs-built_in, - .hljs-title.class_, - .hljs-class .hljs-title { - color: #e6c07b; - } - - .hljs-emphasis { - font-style: italic; - } - - .hljs-strong { - font-weight: bold; - } - - .hljs-link { - text-decoration: underline; - } -} diff --git a/src/components/highlight-code/styles/index.less b/src/components/highlight-code/styles/index.less deleted file mode 100644 index 59d75006..00000000 --- a/src/components/highlight-code/styles/index.less +++ /dev/null @@ -1,84 +0,0 @@ -.high-light-wrapper { - text-align: left; - font-size: var(--font-size-code); - - .hljs { - font-weight: var(--font-weight-normal); - padding-inline: 0; - padding-block: 1.2em; - - &::-webkit-scrollbar { - height: var(--scrollbar-size); - } - - &::-webkit-scrollbar-thumb { - background-color: transparent; - border-radius: 4px; - } - - &::-webkit-scrollbar-track { - background-color: transparent; - } - - &.light { - &:hover { - &::-webkit-scrollbar-thumb { - background-color: var(--color-scrollbar-thumb); - border-radius: 4px; - } - } - } - - &.dark { - &:hover { - &::-webkit-scrollbar-thumb { - background-color: var(--scrollbar-handle-light-bg); - border-radius: 4px; - } - } - } - } - - .code-pre { - padding-inline: 12px 12px; - border-radius: 0 0 var(--border-radius-mini) var(--border-radius-mini); - position: relative; - white-space: pre-wrap; - - code { - line-height: 1.6; - } - - &.copyable { - padding-inline: 12px 32px; - } - - .copy-button { - position: absolute; - top: 6px; - right: 6px; - } - - &.dark { - background-color: var(--color-editor-dark); - - &:hover { - &::-webkit-scrollbar-thumb { - background-color: var(--scrollbar-handle-light-bg); - border-radius: 4px; - } - } - } - - &.light { - background-color: rgb(250, 250, 250); - - &:hover { - &::-webkit-scrollbar-thumb { - background-color: var(--color-scrollbar-thumb); - border-radius: 4px; - } - } - } - } -} diff --git a/src/components/highlight-code/styles/light.less b/src/components/highlight-code/styles/light.less deleted file mode 100644 index d0702775..00000000 --- a/src/components/highlight-code/styles/light.less +++ /dev/null @@ -1,106 +0,0 @@ -// @ts-ingore -pre code.hljs { - display: block; - overflow-x: auto; - padding: 1em; -} - -code.hljs { - padding: 3px 5px; -} - -/* - -Atom One Light by Daniel Gamage -Original One Light Syntax theme from https://github.com/atom/one-light-syntax - -base: #fafafa -mono-1: #383a42 -mono-2: #686b77 -mono-3: #a0a1a7 -hue-1: #0184bb -hue-2: #4078f2 -hue-3: #a626a4 -hue-4: #50a14f -hue-5: #e45649 -hue-5-2: #c91243 -hue-6: #986801 -hue-6-2: #c18401 - -*/ -.code-pre.light { - .hljs { - color: #383a42; - background: var(--color-editor-light); - } - - .hljs-comment, - .hljs-quote { - color: #a0a1a7; - font-style: italic; - } - - .hljs-doctag, - .hljs-keyword, - .hljs-formula { - color: #a626a4; - } - - .hljs-section, - .hljs-name, - .hljs-selector-tag, - .hljs-deletion, - .hljs-subst { - color: #e45649; - } - - .hljs-literal { - color: #0184bb; - } - - .hljs-string, - .hljs-regexp, - .hljs-addition, - .hljs-attribute, - .hljs-meta .hljs-string { - color: #50a14f; - } - - .hljs-attr, - .hljs-variable, - .hljs-template-variable, - .hljs-type, - .hljs-selector-class, - .hljs-selector-attr, - .hljs-selector-pseudo, - .hljs-number { - color: #986801; - } - - .hljs-symbol, - .hljs-bullet, - .hljs-link, - .hljs-meta, - .hljs-selector-id, - .hljs-title { - color: #4078f2; - } - - .hljs-built_in, - .hljs-title.class_, - .hljs-class .hljs-title { - color: #c18401; - } - - .hljs-emphasis { - font-style: italic; - } - - .hljs-strong { - font-weight: bold; - } - - .hljs-link { - text-decoration: underline; - } -} diff --git a/src/components/highlight-code/utils.ts b/src/components/highlight-code/utils.ts deleted file mode 100644 index 76fbce35..00000000 --- a/src/components/highlight-code/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -export function escapeHtml(value: string): string { - return value - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} diff --git a/src/components/icon-font/iconfont/iconfont.css b/src/components/icon-font/iconfont/iconfont.css deleted file mode 100644 index 11df1d0d..00000000 --- a/src/components/icon-font/iconfont/iconfont.css +++ /dev/null @@ -1,915 +0,0 @@ -@font-face { - font-family: iconfont; /* Project id 4613488 */ - src: url('iconfont.woff2?t=1770985961668') format('woff2'), - url('iconfont.woff?t=1770985961668') format('woff'), - url('iconfont.ttf?t=1770985961668') format('truetype'); -} - -.iconfont { - font-family: iconfont !important; - font-size: 16px; - font-style: normal; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.icon-grafana::before { - content: "\e61e"; -} - -.icon-chart::before { - content: "\e6da"; -} - -.icon-monitor-02::before { - content: "\e6d9"; -} - -.icon-monitor::before { - content: "\e6d8"; -} - -.icon-metrics::before { - content: "\e6d6"; -} - -.icon-export::before { - content: "\e6d7"; -} - -.icon-license::before { - content: "\e6d5"; -} - -.icon-community::before { - content: "\e6d3"; -} - -.icon-person::before { - content: "\e6d4"; -} - -.icon-public::before { - content: "\e6d2"; -} - -.icon-charger::before { - content: "\e6d0"; -} - -.icon-disabled::before { - content: "\e6d1"; -} - -.icon-source::before { - content: "\e6cf"; -} - -.icon-Serviceprovider::before { - content: "\e630"; -} - -.icon-database::before { - content: "\e6ce"; -} - -.icon-filters::before { - content: "\e6cc"; -} - -.icon-speed-filled::before { - content: "\e6cb"; -} - -.icon-shield::before { - content: "\e6c9"; -} - -.icon-shield-filled::before { - content: "\e6ca"; -} - -.icon-openai::before { - content: "\e61d"; -} - -.icon-anthropic::before { - content: "\e74d"; -} - -.icon-doubao::before { - content: "\e618"; -} - -.icon-qwen::before { - content: "\e8b2"; -} - -.icon-deepseek::before { - content: "\e61c"; -} - -.icon-extension-outline::before { - content: "\e6c7"; -} - -.icon-extension-filled::before { - content: "\e6c8"; -} - -.icon-thead::before { - content: "\e617"; -} - -.icon-video-filled02::before { - content: "\e6c5"; -} - -.icon-video-outline::before { - content: "\e6c6"; -} - -.icon-video::before { - content: "\e6c3"; -} - -.icon-video-filled::before { - content: "\e6c4"; -} - -.icon-refresh::before { - content: "\e6c2"; -} - -.icon-settings-02::before { - content: "\e6bf"; -} - -.icon-arrow_forward::before { - content: "\e6c0"; -} - -.icon-logout::before { - content: "\e6c1"; -} - -.icon-amd-logo::before { - content: "\e6be"; -} - -.icon-cloud::before { - content: "\e6bc"; -} - -.icon-server02::before { - content: "\e6bd"; -} - -.icon-drag_handle::before { - content: "\e6b9"; -} - -.icon-basic::before { - content: "\e6bb"; -} - -.icon-settings::before { - content: "\e6b8"; -} - -.icon-speed::before { - content: "\e6ba"; -} - -.icon-permission::before { - content: "\e6b6"; -} - -.icon-captive_portal::before { - content: "\e6b7"; -} - -.icon-lock_open_right::before { - content: "\e6b3"; -} - -.icon-lock_person::before { - content: "\e6b4"; -} - -.icon-lock_open::before { - content: "\e6b5"; -} - -.icon-question::before { - content: "\e6b2"; -} - -.icon-aws::before { - content: "\e616"; -} - -.icon-aws1::before { - content: "\e62f"; -} - -.icon-manage_user::before { - content: "\e6b1"; -} - -.icon-private::before { - content: "\e6b0"; -} - -.icon-stop3::before { - content: "\e6af"; -} - -.icon-version::before { - content: "\e6ae"; -} - -.icon-edit-content::before { - content: "\e6ab"; -} - -.icon-code_block::before { - content: "\e6ac"; -} - -.icon-parameters::before { - content: "\e6ad"; -} - -.icon-backend-filled::before { - content: "\e6a9"; -} - -.icon-backend::before { - content: "\e6aa"; -} - -.icon-down2::before { - content: "\e6a7"; -} - -.icon-nvidia2::before { - content: "\e60d"; -} - -.icon-centos::before { - content: "\e6cd"; -} - -.icon-redhat::before { - content: "\ec7b"; -} - -.icon-ubuntu::before { - content: "\edd3"; -} - -.icon-debian::before { - content: "\eb74"; -} - -.icon-alma-linux::before { - content: "\e6a8"; -} - -.icon-fedora::before { - content: "\e61a"; -} - -.icon-rocky-linux::before { - content: "\e620"; -} - -.icon-nvidia1::before { - content: "\e980"; -} - -.icon-nvidia::before { - content: "\e60c"; -} - -.icon-amd::before { - content: "\e6a6"; -} - -.icon-huawei::before { - content: "\e615"; -} - -.icon-metax::before { - content: "\e6a4"; -} - -.icon-ascend::before { - content: "\e6a3"; -} - -.icon-huaweicloud::before { - content: "\e614"; -} - -.icon-alicloud::before { - content: "\e784"; -} - -.icon-tencentcloud::before { - content: "\e609"; -} - -.icon-cluster2-outline::before { - content: "\e6a1"; -} - -.icon-cluster2-filled::before { - content: "\e6a2"; -} - -.icon-cluster-filled::before { - content: "\e69f"; -} - -.icon-cluster-outline::before { - content: "\e6a0"; -} - -.icon-admin-user::before { - content: "\e69d"; -} - -.icon-user::before { - content: "\e69e"; -} - -.icon-detail-info::before { - content: "\e69b"; -} - -.icon-docker::before { - content: "\e69c"; -} - -.icon-digitalocean::before { - content: "\eb79"; -} - -.icon-rocket-launch1::before { - content: "\e699"; -} - -.icon-rocket-launch-fill::before { - content: "\e69a"; -} - -.icon-credential-filled::before { - content: "\e697"; -} - -.icon-credential-outline::before { - content: "\e698"; -} - -.icon-k8s-filled::before { - content: "\e63e"; -} - -.icon-k8s-outline::before { - content: "\e64b"; -} - -.icon-huggingface1::before { - content: "\e605"; -} - -.icon-modelscope_light::before { - content: "\e696"; -} - -.icon-catalog1::before { - content: "\e691"; -} - -.icon-chat-filled::before { - content: "\e692"; -} - -.icon-chat::before { - content: "\e693"; -} - -.icon-files-filled::before { - content: "\e694"; -} - -.icon-files::before { - content: "\e695"; -} - -.icon-models-filled::before { - content: "\e682"; -} - -.icon-image-filled::before { - content: "\e683"; -} - -.icon-audio1::before { - content: "\e684"; -} - -.icon-image1::before { - content: "\e685"; -} - -.icon-audio-filled::before { - content: "\e686"; -} - -.icon-reranker-filled::before { - content: "\e687"; -} - -.icon-embedding-filled::before { - content: "\e68a"; -} - -.icon-models::before { - content: "\e68b"; -} - -.icon-reranker::before { - content: "\e68c"; -} - -.icon-embedding::before { - content: "\e68d"; -} - -.icon-gpu-filled::before { - content: "\e68e"; -} - -.icon-catalog-filled::before { - content: "\e68f"; -} - -.icon-gpu1::before { - content: "\e690"; -} - -.icon-language::before { - content: "\e679"; -} - -.icon-help::before { - content: "\e67a"; -} - -.icon-key-filled::before { - content: "\e67b"; -} - -.icon-key::before { - content: "\e67d"; -} - -.icon-resources::before { - content: "\e67e"; -} - -.icon-users::before { - content: "\e67f"; -} - -.icon-resources-filled::before { - content: "\e680"; -} - -.icon-users-filled::before { - content: "\e681"; -} - -.icon-model::before { - content: "\e676"; -} - -.icon-model-filled::before { - content: "\e678"; -} - -.icon-layers-filled::before { - content: "\e671"; -} - -.icon-layers::before { - content: "\e673"; -} - -.icon-experiment::before { - content: "\e674"; -} - -.icon-experiment-filled::before { - content: "\e675"; -} - -.icon-dashboard::before { - content: "\e66d"; -} - -.icon-dashboard-filled::before { - content: "\e66e"; -} - -.icon-expand-left::before { - content: "\ea48"; -} - -.icon-expand-right::before { - content: "\ea49"; -} - -.icon-users-fill::before { - content: "\e677"; -} - -.icon-layers-fill::before { - content: "\e89d"; -} - -.icon-key-fill::before { - content: "\e80e"; -} - -.icon-server-fill::before { - content: "\e7a3"; -} - -.icon-model-fill::before { - content: "\e7b7"; -} - -.icon-left_panel_close::before { - content: "\e668"; -} - -.icon-left_panel_open::before { - content: "\e669"; -} - -.icon-playcircle-fill::before { - content: "\e665"; -} - -.icon-stopcircle-fill::before { - content: "\e666"; -} - -.icon-play-speed::before { - content: "\e856"; -} - -.icon-more::before { - content: "\e62e"; -} - -.icon-play::before { - content: "\e9f9"; -} - -.icon-pause::before { - content: "\e713"; -} - -.icon-dark_theme::before { - content: "\e646"; -} - -.icon-theme-auto-1::before { - content: "\e660"; -} - -.icon-theme-auto::before { - content: "\e663"; -} - -.icon-auto-theme-1::before { - content: "\e664"; -} - -.icon-auto-theme::before { - content: "\e662"; -} - -.icon-cols_3::before { - content: "\e65c"; -} - -.icon-cols_6::before { - content: "\e65d"; -} - -.icon-cols_2::before { - content: "\e65e"; -} - -.icon-cols_4::before { - content: "\e65f"; -} - -.icon-a-save1::before { - content: "\e65b"; -} - -.icon-uncollapse_all::before { - content: "\e657"; -} - -.icon-collapse::before { - content: "\e656"; -} - -.icon-rocket-launch::before { - content: "\e689"; -} - -.icon-user-filled::before { - content: "\e625"; -} - -.icon-assistant::before { - content: "\e62d"; -} - -.icon-assistant-filled::before { - content: "\e847"; -} - -.icon-save3::before { - content: "\e655"; -} - -.icon-fankuifaqs::before { - content: "\e7bf"; -} - -.icon-issues::before { - content: "\e816"; -} - -.icon-neicun::before { - content: "\e688"; -} - -.icon-collapse_all::before { - content: "\e66f"; -} - -.icon-down::before { - content: "\e654"; -} - -.icon-fenxiang::before { - content: "\e604"; -} - -.icon-mosaic-2::before { - content: "\e64f"; -} - -.icon-stars::before { - content: "\e8a8"; -} - -.icon-mosaic::before { - content: "\e636"; -} - -.icon-outline-play::before { - content: "\e653"; -} - -.icon-SelectionInverse::before { - content: "\eace"; -} - -.icon-justice1::before { - content: "\e652"; -} - -.icon-New_img::before { - content: "\e733"; -} - -.icon-new_release_outlined::before { - content: "\e66c"; -} - -.icon-new-releases::before { - content: "\e60f"; -} - -.icon-catalog::before { - content: "\e62b"; -} - -.icon-save2::before { - content: "\e635"; -} - -.icon-left-template::before { - content: "\e62a"; -} - -.icon-logs::before { - content: "\e6ec"; -} - -.icon-gpu::before { - content: "\e71e"; -} - -.icon-filled-gpu::before { - content: "\e6de"; -} - -.icon-outline-gpu::before { - content: "\e641"; -} - -.icon-ts-tubiao_webserver::before { - content: "\e716"; -} - -.icon-server::before { - content: "\e66a"; -} - -.icon-host::before { - content: "\e7c6"; -} - -.icon-playcircle::before { - content: "\e80f"; -} - -.icon-recreate::before { - content: "\e6a5"; -} - -.icon-save1::before { - content: "\e647"; -} - -.icon-save::before { - content: "\e67c"; -} - -.icon-upload_image::before { - content: "\e613"; -} - -.icon-sound-wave::before { - content: "\e619"; -} - -.icon-rank1::before { - content: "\e7cb"; -} - -.icon-cube::before { - content: "\e769"; -} - -.icon-speaker-slash::before { - content: "\ebb6"; -} - -.icon-random::before { - content: "\e603"; -} - -.icon-suijisenlin::before { - content: "\e60e"; -} - -.icon-stop2::before { - content: "\e8db"; -} - -.icon-stop::before { - content: "\e60b"; -} - -.icon-image::before { - content: "\e62c"; -} - -.icon-SpeakerSlash::before { - content: "\e661"; -} - -.icon-SpeakerHigh::before { - content: "\e670"; -} - -.icon-user_voice::before { - content: "\e667"; -} - -.icon-audio::before { - content: "\e985"; -} - -.icon-hard-disk::before { - content: "\eb1d"; -} - -.icon-new::before { - content: "\e612"; -} - -.icon-tu2::before { - content: "\e607"; -} - -.icon-robot::before { - content: "\e634"; -} - -.icon-robot1::before { - content: "\e602"; -} - -.icon-aizhineng::before { - content: "\e672"; -} - -.icon-copy::before { - content: "\e720"; -} - -.icon-AIzhineng::before { - content: "\e608"; -} - -.icon-clear::before { - content: "\e60a"; -} - -.icon-keyboard::before { - content: "\e61b"; -} - -.icon-networkerror::before { - content: "\e624"; -} - -.icon-external-link::before { - content: "\e66b"; -} - -.icon-huggingface::before { - content: "\e7d1"; -} - -.icon-ollama::before { - content: "\e601"; -} - -.icon-a-layout6-line::before { - content: "\e9ef"; -} - -.icon-a-Layout5::before { - content: "\e610"; -} - -.icon-English::before { - content: "\e8b3"; -} - -.icon-chinese::before { - content: "\e611"; -} - -.icon-yingguo::before { - content: "\e606"; -} - -.icon-code::before { - content: "\e84f"; -} - -.icon-stop1::before { - content: "\e783"; -} - -.icon-command::before { - content: "\e600"; -} - diff --git a/src/components/icon-font/iconfont/iconfont.js b/src/components/icon-font/iconfont/iconfont.js deleted file mode 100644 index 275cb03f..00000000 --- a/src/components/icon-font/iconfont/iconfont.js +++ /dev/null @@ -1 +0,0 @@ -window._iconfont_svg_string_4613488='',(a=>{var l=(h=(h=document.getElementsByTagName("script"))[h.length-1]).getAttribute("data-injectcss"),h=h.getAttribute("data-disable-injectsvg");if(!h){var v,c,z,t,m,o=function(l,h){h.parentNode.insertBefore(l,h)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}v=function(){var l,h=document.createElement("div");h.innerHTML=a._iconfont_svg_string_4613488,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(l=document.body).firstChild?o(h,l.firstChild):l.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),v()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(z=v,t=a.document,m=!1,i(),t.onreadystatechange=function(){"complete"==t.readyState&&(t.onreadystatechange=null,q())})}function q(){m||(m=!0,z())}function i(){try{t.documentElement.doScroll("left")}catch(l){return void setTimeout(i,50)}q()}})(window); \ No newline at end of file diff --git a/src/components/icon-font/iconfont/iconfont.json b/src/components/icon-font/iconfont/iconfont.json deleted file mode 100644 index 9d53aee0..00000000 --- a/src/components/icon-font/iconfont/iconfont.json +++ /dev/null @@ -1,1584 +0,0 @@ -{ - "id": "4613488", - "name": "gpustack", - "font_family": "iconfont", - "css_prefix_text": "icon-", - "description": "", - "glyphs": [ - { - "icon_id": "31689363", - "name": "grafana (2)", - "font_class": "grafana", - "unicode": "e61e", - "unicode_decimal": 58910 - }, - { - "icon_id": "46845894", - "name": "chart", - "font_class": "chart", - "unicode": "e6da", - "unicode_decimal": 59098 - }, - { - "icon_id": "46844385", - "name": "monitor", - "font_class": "monitor-02", - "unicode": "e6d9", - "unicode_decimal": 59097 - }, - { - "icon_id": "46842822", - "name": "monitor", - "font_class": "monitor", - "unicode": "e6d8", - "unicode_decimal": 59096 - }, - { - "icon_id": "46821022", - "name": "metrics", - "font_class": "metrics", - "unicode": "e6d6", - "unicode_decimal": 59094 - }, - { - "icon_id": "46812763", - "name": "export", - "font_class": "export", - "unicode": "e6d7", - "unicode_decimal": 59095 - }, - { - "icon_id": "46802651", - "name": "license", - "font_class": "license", - "unicode": "e6d5", - "unicode_decimal": 59093 - }, - { - "icon_id": "46790594", - "name": "crowdsource_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz24", - "font_class": "community", - "unicode": "e6d3", - "unicode_decimal": 59091 - }, - { - "icon_id": "46790593", - "name": "person_celebrate_24dp_1F1F1F_FILL0_wght300_GRAD0_o", - "font_class": "person", - "unicode": "e6d4", - "unicode_decimal": 59092 - }, - { - "icon_id": "46790615", - "name": "public_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz24", - "font_class": "public", - "unicode": "e6d2", - "unicode_decimal": 59090 - }, - { - "icon_id": "46783187", - "name": "charger", - "font_class": "charger", - "unicode": "e6d0", - "unicode_decimal": 59088 - }, - { - "icon_id": "46783186", - "name": "disabled", - "font_class": "disabled", - "unicode": "e6d1", - "unicode_decimal": 59089 - }, - { - "icon_id": "46775558", - "name": "source", - "font_class": "source", - "unicode": "e6cf", - "unicode_decimal": 59087 - }, - { - "icon_id": "2735079", - "name": "Service provider", - "font_class": "Serviceprovider", - "unicode": "e630", - "unicode_decimal": 58928 - }, - { - "icon_id": "46719213", - "name": "database_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz24", - "font_class": "database", - "unicode": "e6ce", - "unicode_decimal": 59086 - }, - { - "icon_id": "46714731", - "name": "manage_search_24dp_1F1F1F_FILL1_wght300_GRAD0_opsz", - "font_class": "filters", - "unicode": "e6cc", - "unicode_decimal": 59084 - }, - { - "icon_id": "46703055", - "name": "speed_24dp_1F1F1F_FILL1_wght300_GRAD0_opsz24", - "font_class": "speed-filled", - "unicode": "e6cb", - "unicode_decimal": 59083 - }, - { - "icon_id": "46702137", - "name": "shield_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz24", - "font_class": "shield", - "unicode": "e6c9", - "unicode_decimal": 59081 - }, - { - "icon_id": "46702136", - "name": "shield_24dp_1F1F1F_FILL1_wght300_GRAD0_opsz24", - "font_class": "shield-filled", - "unicode": "e6ca", - "unicode_decimal": 59082 - }, - { - "icon_id": "42735715", - "name": "openai", - "font_class": "openai", - "unicode": "e61d", - "unicode_decimal": 58909 - }, - { - "icon_id": "39934600", - "name": "anthropic", - "font_class": "anthropic", - "unicode": "e74d", - "unicode_decimal": 59213 - }, - { - "icon_id": "40532962", - "name": "doubao", - "font_class": "doubao", - "unicode": "e618", - "unicode_decimal": 58904 - }, - { - "icon_id": "43558740", - "name": "QWen", - "font_class": "qwen", - "unicode": "e8b2", - "unicode_decimal": 59570 - }, - { - "icon_id": "43616544", - "name": "deepseek-copy", - "font_class": "deepseek", - "unicode": "e61c", - "unicode_decimal": 58908 - }, - { - "icon_id": "46650646", - "name": "extension_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz24", - "font_class": "extension-outline", - "unicode": "e6c7", - "unicode_decimal": 59079 - }, - { - "icon_id": "46650645", - "name": "extension_24dp_1F1F1F_FILL1_wght300_GRAD0_opsz24", - "font_class": "extension-filled", - "unicode": "e6c8", - "unicode_decimal": 59080 - }, - { - "icon_id": "43960229", - "name": "thead", - "font_class": "thead", - "unicode": "e617", - "unicode_decimal": 58903 - }, - { - "icon_id": "46626616", - "name": "video-filled02", - "font_class": "video-filled02", - "unicode": "e6c5", - "unicode_decimal": 59077 - }, - { - "icon_id": "46626615", - "name": "video-outline", - "font_class": "video-outline", - "unicode": "e6c6", - "unicode_decimal": 59078 - }, - { - "icon_id": "46616487", - "name": "video", - "font_class": "video", - "unicode": "e6c3", - "unicode_decimal": 59075 - }, - { - "icon_id": "46616486", - "name": "video-filled", - "font_class": "video-filled", - "unicode": "e6c4", - "unicode_decimal": 59076 - }, - { - "icon_id": "46569108", - "name": "refresh", - "font_class": "refresh", - "unicode": "e6c2", - "unicode_decimal": 59074 - }, - { - "icon_id": "46569091", - "name": "settings", - "font_class": "settings-02", - "unicode": "e6bf", - "unicode_decimal": 59071 - }, - { - "icon_id": "46569092", - "name": "arrow_forward", - "font_class": "arrow_forward", - "unicode": "e6c0", - "unicode_decimal": 59072 - }, - { - "icon_id": "46569093", - "name": "logout", - "font_class": "logout", - "unicode": "e6c1", - "unicode_decimal": 59073 - }, - { - "icon_id": "46548884", - "name": "amd-logo", - "font_class": "amd-logo", - "unicode": "e6be", - "unicode_decimal": 59070 - }, - { - "icon_id": "46296038", - "name": "cloud", - "font_class": "cloud", - "unicode": "e6bc", - "unicode_decimal": 59068 - }, - { - "icon_id": "46296037", - "name": "server", - "font_class": "server02", - "unicode": "e6bd", - "unicode_decimal": 59069 - }, - { - "icon_id": "46272083", - "name": "drag_handle", - "font_class": "drag_handle", - "unicode": "e6b9", - "unicode_decimal": 59065 - }, - { - "icon_id": "46055620", - "name": "basic", - "font_class": "basic", - "unicode": "e6bb", - "unicode_decimal": 59067 - }, - { - "icon_id": "46055265", - "name": "settings", - "font_class": "settings", - "unicode": "e6b8", - "unicode_decimal": 59064 - }, - { - "icon_id": "46055263", - "name": "speed", - "font_class": "speed", - "unicode": "e6ba", - "unicode_decimal": 59066 - }, - { - "icon_id": "46039838", - "name": "permission", - "font_class": "permission", - "unicode": "e6b6", - "unicode_decimal": 59062 - }, - { - "icon_id": "46039837", - "name": "captive_portal", - "font_class": "captive_portal", - "unicode": "e6b7", - "unicode_decimal": 59063 - }, - { - "icon_id": "46001737", - "name": "lock_open_right", - "font_class": "lock_open_right", - "unicode": "e6b3", - "unicode_decimal": 59059 - }, - { - "icon_id": "46001736", - "name": "lock_person", - "font_class": "lock_person", - "unicode": "e6b4", - "unicode_decimal": 59060 - }, - { - "icon_id": "46001735", - "name": "lock_open", - "font_class": "lock_open", - "unicode": "e6b5", - "unicode_decimal": 59061 - }, - { - "icon_id": "45937227", - "name": "question_mark_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz", - "font_class": "question", - "unicode": "e6b2", - "unicode_decimal": 59058 - }, - { - "icon_id": "10786885", - "name": "aws", - "font_class": "aws", - "unicode": "e616", - "unicode_decimal": 58902 - }, - { - "icon_id": "12014352", - "name": "aws", - "font_class": "aws1", - "unicode": "e62f", - "unicode_decimal": 58927 - }, - { - "icon_id": "45704693", - "name": "manage_accounts_24dp_1F1F1F_FILL1_wght300_GRAD0_op", - "font_class": "manage_user", - "unicode": "e6b1", - "unicode_decimal": 59057 - }, - { - "icon_id": "45702717", - "name": "private", - "font_class": "private", - "unicode": "e6b0", - "unicode_decimal": 59056 - }, - { - "icon_id": "45702697", - "name": "stop", - "font_class": "stop3", - "unicode": "e6af", - "unicode_decimal": 59055 - }, - { - "icon_id": "45688107", - "name": "version", - "font_class": "version", - "unicode": "e6ae", - "unicode_decimal": 59054 - }, - { - "icon_id": "45631011", - "name": "contract_edit_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz", - "font_class": "edit-content", - "unicode": "e6ab", - "unicode_decimal": 59051 - }, - { - "icon_id": "45631010", - "name": "code_blocks_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz24", - "font_class": "code_block", - "unicode": "e6ac", - "unicode_decimal": 59052 - }, - { - "icon_id": "45631009", - "name": "settings_applications_24dp_1F1F1F_FILL0_wght300_GR", - "font_class": "parameters", - "unicode": "e6ad", - "unicode_decimal": 59053 - }, - { - "icon_id": "45623375", - "name": "bolt_24dp_1F1F1F_FILL1_wght300_GRAD0_opsz24", - "font_class": "backend-filled", - "unicode": "e6a9", - "unicode_decimal": 59049 - }, - { - "icon_id": "45623374", - "name": "bolt_24dp_1F1F1F_FILL0_wght300_GRAD0_opsz24", - "font_class": "backend", - "unicode": "e6aa", - "unicode_decimal": 59050 - }, - { - "icon_id": "45554217", - "name": "arrow_down", - "font_class": "down2", - "unicode": "e6a7", - "unicode_decimal": 59047 - }, - { - "icon_id": "11155543", - "name": "nvidia", - "font_class": "nvidia2", - "unicode": "e60d", - "unicode_decimal": 58893 - }, - { - "icon_id": "11425971", - "name": "centos", - "font_class": "centos", - "unicode": "e6cd", - "unicode_decimal": 59085 - }, - { - "icon_id": "15378743", - "name": "redhat", - "font_class": "redhat", - "unicode": "ec7b", - "unicode_decimal": 60539 - }, - { - "icon_id": "6808499", - "name": "Ubuntu", - "font_class": "ubuntu", - "unicode": "edd3", - "unicode_decimal": 60883 - }, - { - "icon_id": "15378275", - "name": "debian", - "font_class": "debian", - "unicode": "eb74", - "unicode_decimal": 60276 - }, - { - "icon_id": "38395859", - "name": "almalinux", - "font_class": "alma-linux", - "unicode": "e6a8", - "unicode_decimal": 59048 - }, - { - "icon_id": "43280042", - "name": "linux-fedora", - "font_class": "fedora", - "unicode": "e61a", - "unicode_decimal": 58906 - }, - { - "icon_id": "43280143", - "name": "linux-rocky_linux", - "font_class": "rocky-linux", - "unicode": "e620", - "unicode_decimal": 58912 - }, - { - "icon_id": "36227448", - "name": "nvidia", - "font_class": "nvidia1", - "unicode": "e980", - "unicode_decimal": 59776 - }, - { - "icon_id": "40723469", - "name": "nvidia", - "font_class": "nvidia", - "unicode": "e60c", - "unicode_decimal": 58892 - }, - { - "icon_id": "45463937", - "name": "amd", - "font_class": "amd", - "unicode": "e6a6", - "unicode_decimal": 59046 - }, - { - "icon_id": "24164616", - "name": "华为", - "font_class": "huawei", - "unicode": "e615", - "unicode_decimal": 58901 - }, - { - "icon_id": "45461362", - "name": "metax", - "font_class": "metax", - "unicode": "e6a4", - "unicode_decimal": 59044 - }, - { - "icon_id": "45459906", - "name": "ascend", - "font_class": "ascend", - "unicode": "e6a3", - "unicode_decimal": 59043 - }, - { - "icon_id": "8152996", - "name": "HUAWEI", - "font_class": "huaweicloud", - "unicode": "e614", - "unicode_decimal": 58900 - }, - { - "icon_id": "34290284", - "name": "alicloud", - "font_class": "alicloud", - "unicode": "e784", - "unicode_decimal": 59268 - }, - { - "icon_id": "36654764", - "name": "tencent", - "font_class": "tencentcloud", - "unicode": "e609", - "unicode_decimal": 58889 - }, - { - "icon_id": "45310241", - "name": "cluster2-outline", - "font_class": "cluster2-outline", - "unicode": "e6a1", - "unicode_decimal": 59041 - }, - { - "icon_id": "45310242", - "name": "cluster2-filled", - "font_class": "cluster2-filled", - "unicode": "e6a2", - "unicode_decimal": 59042 - }, - { - "icon_id": "45310070", - "name": "cluster-filled", - "font_class": "cluster-filled", - "unicode": "e69f", - "unicode_decimal": 59039 - }, - { - "icon_id": "45310069", - "name": "cluster-outline", - "font_class": "cluster-outline", - "unicode": "e6a0", - "unicode_decimal": 59040 - }, - { - "icon_id": "45240470", - "name": "admin-user", - "font_class": "admin-user", - "unicode": "e69d", - "unicode_decimal": 59037 - }, - { - "icon_id": "45240469", - "name": "user", - "font_class": "user", - "unicode": "e69e", - "unicode_decimal": 59038 - }, - { - "icon_id": "45221182", - "name": "detail-info", - "font_class": "detail-info", - "unicode": "e69b", - "unicode_decimal": 59035 - }, - { - "icon_id": "45102077", - "name": "Docker", - "font_class": "docker", - "unicode": "e69c", - "unicode_decimal": 59036 - }, - { - "icon_id": "15378290", - "name": "digitalocean", - "font_class": "digitalocean", - "unicode": "eb79", - "unicode_decimal": 60281 - }, - { - "icon_id": "45040302", - "name": "rocket-launch", - "font_class": "rocket-launch1", - "unicode": "e699", - "unicode_decimal": 59033 - }, - { - "icon_id": "45040301", - "name": "rocket-launch-fill", - "font_class": "rocket-launch-fill", - "unicode": "e69a", - "unicode_decimal": 59034 - }, - { - "icon_id": "45028316", - "name": "credential", - "font_class": "credential-filled", - "unicode": "e697", - "unicode_decimal": 59031 - }, - { - "icon_id": "45028315", - "name": "credential", - "font_class": "credential-outline", - "unicode": "e698", - "unicode_decimal": 59032 - }, - { - "icon_id": "37601405", - "name": "k8s", - "font_class": "k8s-filled", - "unicode": "e63e", - "unicode_decimal": 58942 - }, - { - "icon_id": "41673174", - "name": "k8s", - "font_class": "k8s-outline", - "unicode": "e64b", - "unicode_decimal": 58955 - }, - { - "icon_id": "40865292", - "name": "huggingface", - "font_class": "huggingface1", - "unicode": "e605", - "unicode_decimal": 58885 - }, - { - "icon_id": "43616582", - "name": "modelscope_light", - "font_class": "modelscope_light", - "unicode": "e696", - "unicode_decimal": 59030 - }, - { - "icon_id": "44776845", - "name": "catalog", - "font_class": "catalog1", - "unicode": "e691", - "unicode_decimal": 59025 - }, - { - "icon_id": "44776848", - "name": "chat-filled", - "font_class": "chat-filled", - "unicode": "e692", - "unicode_decimal": 59026 - }, - { - "icon_id": "44776846", - "name": "chat", - "font_class": "chat", - "unicode": "e693", - "unicode_decimal": 59027 - }, - { - "icon_id": "44776841", - "name": "files-filled", - "font_class": "files-filled", - "unicode": "e694", - "unicode_decimal": 59028 - }, - { - "icon_id": "44776840", - "name": "files", - "font_class": "files", - "unicode": "e695", - "unicode_decimal": 59029 - }, - { - "icon_id": "44776851", - "name": "models-filled", - "font_class": "models-filled", - "unicode": "e682", - "unicode_decimal": 59010 - }, - { - "icon_id": "44776857", - "name": "image-filled", - "font_class": "image-filled", - "unicode": "e683", - "unicode_decimal": 59011 - }, - { - "icon_id": "44776856", - "name": "audio", - "font_class": "audio1", - "unicode": "e684", - "unicode_decimal": 59012 - }, - { - "icon_id": "44776855", - "name": "image", - "font_class": "image1", - "unicode": "e685", - "unicode_decimal": 59013 - }, - { - "icon_id": "44776850", - "name": "audio-filled", - "font_class": "audio-filled", - "unicode": "e686", - "unicode_decimal": 59014 - }, - { - "icon_id": "44776849", - "name": "reranker-filled", - "font_class": "reranker-filled", - "unicode": "e687", - "unicode_decimal": 59015 - }, - { - "icon_id": "44776852", - "name": "embedding-filled", - "font_class": "embedding-filled", - "unicode": "e68a", - "unicode_decimal": 59018 - }, - { - "icon_id": "44776853", - "name": "models", - "font_class": "models", - "unicode": "e68b", - "unicode_decimal": 59019 - }, - { - "icon_id": "44776844", - "name": "reranker", - "font_class": "reranker", - "unicode": "e68c", - "unicode_decimal": 59020 - }, - { - "icon_id": "44776854", - "name": "embedding", - "font_class": "embedding", - "unicode": "e68d", - "unicode_decimal": 59021 - }, - { - "icon_id": "44776843", - "name": "gpu-filled", - "font_class": "gpu-filled", - "unicode": "e68e", - "unicode_decimal": 59022 - }, - { - "icon_id": "44776847", - "name": "catalog-filled", - "font_class": "catalog-filled", - "unicode": "e68f", - "unicode_decimal": 59023 - }, - { - "icon_id": "44776842", - "name": "gpu", - "font_class": "gpu1", - "unicode": "e690", - "unicode_decimal": 59024 - }, - { - "icon_id": "44685190", - "name": "language", - "font_class": "language", - "unicode": "e679", - "unicode_decimal": 59001 - }, - { - "icon_id": "44685189", - "name": "help", - "font_class": "help", - "unicode": "e67a", - "unicode_decimal": 59002 - }, - { - "icon_id": "44684306", - "name": "key-filled", - "font_class": "key-filled", - "unicode": "e67b", - "unicode_decimal": 59003 - }, - { - "icon_id": "44684302", - "name": "key", - "font_class": "key", - "unicode": "e67d", - "unicode_decimal": 59005 - }, - { - "icon_id": "44684304", - "name": "resources", - "font_class": "resources", - "unicode": "e67e", - "unicode_decimal": 59006 - }, - { - "icon_id": "44684305", - "name": "users", - "font_class": "users", - "unicode": "e67f", - "unicode_decimal": 59007 - }, - { - "icon_id": "44684303", - "name": "resources-filled", - "font_class": "resources-filled", - "unicode": "e680", - "unicode_decimal": 59008 - }, - { - "icon_id": "44684301", - "name": "users-filled", - "font_class": "users-filled", - "unicode": "e681", - "unicode_decimal": 59009 - }, - { - "icon_id": "44684150", - "name": "model", - "font_class": "model", - "unicode": "e676", - "unicode_decimal": 58998 - }, - { - "icon_id": "44684149", - "name": "model-filled", - "font_class": "model-filled", - "unicode": "e678", - "unicode_decimal": 59000 - }, - { - "icon_id": "44684090", - "name": "layers-filled", - "font_class": "layers-filled", - "unicode": "e671", - "unicode_decimal": 58993 - }, - { - "icon_id": "44684091", - "name": "layers", - "font_class": "layers", - "unicode": "e673", - "unicode_decimal": 58995 - }, - { - "icon_id": "44684086", - "name": "experiment", - "font_class": "experiment", - "unicode": "e674", - "unicode_decimal": 58996 - }, - { - "icon_id": "44684085", - "name": "experiment", - "font_class": "experiment-filled", - "unicode": "e675", - "unicode_decimal": 58997 - }, - { - "icon_id": "44684021", - "name": "dashboard", - "font_class": "dashboard", - "unicode": "e66d", - "unicode_decimal": 58989 - }, - { - "icon_id": "44684020", - "name": "dashboard-filled", - "font_class": "dashboard-filled", - "unicode": "e66e", - "unicode_decimal": 58990 - }, - { - "icon_id": "40068272", - "name": "expand-left", - "font_class": "expand-left", - "unicode": "ea48", - "unicode_decimal": 59976 - }, - { - "icon_id": "40068278", - "name": "expand-right", - "font_class": "expand-right", - "unicode": "ea49", - "unicode_decimal": 59977 - }, - { - "icon_id": "1350497", - "name": "sq-users", - "font_class": "users-fill", - "unicode": "e677", - "unicode_decimal": 58999 - }, - { - "icon_id": "13691715", - "name": "layers", - "font_class": "layers-fill", - "unicode": "e89d", - "unicode_decimal": 59549 - }, - { - "icon_id": "14267903", - "name": "key-skeleton-alt", - "font_class": "key-fill", - "unicode": "e80e", - "unicode_decimal": 59406 - }, - { - "icon_id": "14341823", - "name": "cloud-server-solid", - "font_class": "server-fill", - "unicode": "e7a3", - "unicode_decimal": 59299 - }, - { - "icon_id": "40764011", - "name": "icon-model-selected", - "font_class": "model-fill", - "unicode": "e7b7", - "unicode_decimal": 59319 - }, - { - "icon_id": "44668359", - "name": "left_panel_close_36dp_1F1F1F_FILL0_wght400_GRAD0_o", - "font_class": "left_panel_close", - "unicode": "e668", - "unicode_decimal": 58984 - }, - { - "icon_id": "44668360", - "name": "left_panel_open_36dp_1F1F1F_FILL0_wght400_GRAD0_op", - "font_class": "left_panel_open", - "unicode": "e669", - "unicode_decimal": 58985 - }, - { - "icon_id": "44650419", - "name": "play circle-fill", - "font_class": "playcircle-fill", - "unicode": "e665", - "unicode_decimal": 58981 - }, - { - "icon_id": "44650418", - "name": "stop circle-fill", - "font_class": "stopcircle-fill", - "unicode": "e666", - "unicode_decimal": 58982 - }, - { - "icon_id": "8592899", - "name": "play-speed", - "font_class": "play-speed", - "unicode": "e856", - "unicode_decimal": 59478 - }, - { - "icon_id": "10941162", - "name": "more", - "font_class": "more", - "unicode": "e62e", - "unicode_decimal": 58926 - }, - { - "icon_id": "703373", - "name": "play", - "font_class": "play", - "unicode": "e9f9", - "unicode_decimal": 59897 - }, - { - "icon_id": "736882", - "name": "pause", - "font_class": "pause", - "unicode": "e713", - "unicode_decimal": 59155 - }, - { - "icon_id": "44028047", - "name": "dark_theme", - "font_class": "dark_theme", - "unicode": "e646", - "unicode_decimal": 58950 - }, - { - "icon_id": "44094552", - "name": "theme-auto-1", - "font_class": "theme-auto-1", - "unicode": "e660", - "unicode_decimal": 58976 - }, - { - "icon_id": "44094551", - "name": "theme-auto", - "font_class": "theme-auto", - "unicode": "e663", - "unicode_decimal": 58979 - }, - { - "icon_id": "44094550", - "name": "theme", - "font_class": "auto-theme-1", - "unicode": "e664", - "unicode_decimal": 58980 - }, - { - "icon_id": "44092227", - "name": "routine_36dp_1F1F1F_FILL0_wght400_GRAD0_opsz24", - "font_class": "auto-theme", - "unicode": "e662", - "unicode_decimal": 58978 - }, - { - "icon_id": "44086334", - "name": "cols_3", - "font_class": "cols_3", - "unicode": "e65c", - "unicode_decimal": 58972 - }, - { - "icon_id": "44086333", - "name": "cols_6", - "font_class": "cols_6", - "unicode": "e65d", - "unicode_decimal": 58973 - }, - { - "icon_id": "44086332", - "name": "cols_2", - "font_class": "cols_2", - "unicode": "e65e", - "unicode_decimal": 58974 - }, - { - "icon_id": "44086331", - "name": "cols_4", - "font_class": "cols_4", - "unicode": "e65f", - "unicode_decimal": 58975 - }, - { - "icon_id": "44065884", - "name": "save", - "font_class": "a-save1", - "unicode": "e65b", - "unicode_decimal": 58971 - }, - { - "icon_id": "43808249", - "name": "uncollapse_all", - "font_class": "uncollapse_all", - "unicode": "e657", - "unicode_decimal": 58967 - }, - { - "icon_id": "43807590", - "name": "collapse", - "font_class": "collapse", - "unicode": "e656", - "unicode_decimal": 58966 - }, - { - "icon_id": "22575690", - "name": "rocket-launch", - "font_class": "rocket-launch", - "unicode": "e689", - "unicode_decimal": 59017 - }, - { - "icon_id": "6050653", - "name": "user", - "font_class": "user-filled", - "unicode": "e625", - "unicode_decimal": 58917 - }, - { - "icon_id": "37486588", - "name": "assistant", - "font_class": "assistant", - "unicode": "e62d", - "unicode_decimal": 58925 - }, - { - "icon_id": "43220044", - "name": "AIAssistant", - "font_class": "assistant-filled", - "unicode": "e847", - "unicode_decimal": 59463 - }, - { - "icon_id": "43626126", - "name": "save", - "font_class": "save3", - "unicode": "e655", - "unicode_decimal": 58965 - }, - { - "icon_id": "20186129", - "name": "反馈faqs", - "font_class": "fankuifaqs", - "unicode": "e7bf", - "unicode_decimal": 59327 - }, - { - "icon_id": "42800361", - "name": "issues", - "font_class": "issues", - "unicode": "e816", - "unicode_decimal": 59414 - }, - { - "icon_id": "8211955", - "name": "ram", - "font_class": "neicun", - "unicode": "e688", - "unicode_decimal": 59016 - }, - { - "icon_id": "37125227", - "name": "collapse_all", - "font_class": "collapse_all", - "unicode": "e66f", - "unicode_decimal": 58991 - }, - { - "icon_id": "43363249", - "name": "down", - "font_class": "down", - "unicode": "e654", - "unicode_decimal": 58964 - }, - { - "icon_id": "159932", - "name": "search", - "font_class": "fenxiang", - "unicode": "e604", - "unicode_decimal": 58884 - }, - { - "icon_id": "40678285", - "name": "mosaic", - "font_class": "mosaic-2", - "unicode": "e64f", - "unicode_decimal": 58959 - }, - { - "icon_id": "22859935", - "name": "stars", - "font_class": "stars", - "unicode": "e8a8", - "unicode_decimal": 59560 - }, - { - "icon_id": "39566959", - "name": "mosaic", - "font_class": "mosaic", - "unicode": "e636", - "unicode_decimal": 58934 - }, - { - "icon_id": "43256197", - "name": "play circle", - "font_class": "outline-play", - "unicode": "e653", - "unicode_decimal": 58963 - }, - { - "icon_id": "27116743", - "name": "SelectionInverse", - "font_class": "SelectionInverse", - "unicode": "eace", - "unicode_decimal": 60110 - }, - { - "icon_id": "43035036", - "name": "justice", - "font_class": "justice1", - "unicode": "e652", - "unicode_decimal": 58962 - }, - { - "icon_id": "1740853", - "name": "New_img", - "font_class": "New_img", - "unicode": "e733", - "unicode_decimal": 59187 - }, - { - "icon_id": "9745732", - "name": "new_release_outlined", - "font_class": "new_release_outlined", - "unicode": "e66c", - "unicode_decimal": 58988 - }, - { - "icon_id": "40667024", - "name": "new-releases", - "font_class": "new-releases", - "unicode": "e60f", - "unicode_decimal": 58895 - }, - { - "icon_id": "41920256", - "name": "catalog", - "font_class": "catalog", - "unicode": "e62b", - "unicode_decimal": 58923 - }, - { - "icon_id": "13851416", - "name": "save", - "font_class": "save2", - "unicode": "e635", - "unicode_decimal": 58933 - }, - { - "icon_id": "3238366", - "name": "模板", - "font_class": "left-template", - "unicode": "e62a", - "unicode_decimal": 58922 - }, - { - "icon_id": "26746089", - "name": "logs", - "font_class": "logs", - "unicode": "e6ec", - "unicode_decimal": 59116 - }, - { - "icon_id": "1132892", - "name": "gpu", - "font_class": "gpu", - "unicode": "e71e", - "unicode_decimal": 59166 - }, - { - "icon_id": "38418656", - "name": "GPUxCPU", - "font_class": "filled-gpu", - "unicode": "e6de", - "unicode_decimal": 59102 - }, - { - "icon_id": "7556336", - "name": "gpu", - "font_class": "outline-gpu", - "unicode": "e641", - "unicode_decimal": 58945 - }, - { - "icon_id": "8040181", - "name": "webserver", - "font_class": "ts-tubiao_webserver", - "unicode": "e716", - "unicode_decimal": 59158 - }, - { - "icon_id": "6587064", - "name": "server", - "font_class": "server", - "unicode": "e66a", - "unicode_decimal": 58986 - }, - { - "icon_id": "40493325", - "name": "host", - "font_class": "host", - "unicode": "e7c6", - "unicode_decimal": 59334 - }, - { - "icon_id": "6151262", - "name": "play circle", - "font_class": "playcircle", - "unicode": "e80f", - "unicode_decimal": 59407 - }, - { - "icon_id": "25197526", - "name": "recreate", - "font_class": "recreate", - "unicode": "e6a5", - "unicode_decimal": 59045 - }, - { - "icon_id": "12689724", - "name": "save", - "font_class": "save1", - "unicode": "e647", - "unicode_decimal": 58951 - }, - { - "icon_id": "15838524", - "name": "save", - "font_class": "save", - "unicode": "e67c", - "unicode_decimal": 59004 - }, - { - "icon_id": "8782480", - "name": "upload_image", - "font_class": "upload_image", - "unicode": "e613", - "unicode_decimal": 58899 - }, - { - "icon_id": "14464883", - "name": "sound-wave", - "font_class": "sound-wave", - "unicode": "e619", - "unicode_decimal": 58905 - }, - { - "icon_id": "37200543", - "name": "rank", - "font_class": "rank1", - "unicode": "e7cb", - "unicode_decimal": 59339 - }, - { - "icon_id": "5127275", - "name": "cube", - "font_class": "cube", - "unicode": "e769", - "unicode_decimal": 59241 - }, - { - "icon_id": "28326047", - "name": "speaker-slash", - "font_class": "speaker-slash", - "unicode": "ebb6", - "unicode_decimal": 60342 - }, - { - "icon_id": "13059398", - "name": "随机", - "font_class": "random", - "unicode": "e603", - "unicode_decimal": 58883 - }, - { - "icon_id": "5978743", - "name": "random-forest", - "font_class": "suijisenlin", - "unicode": "e60e", - "unicode_decimal": 58894 - }, - { - "icon_id": "15617444", - "name": "stop", - "font_class": "stop2", - "unicode": "e8db", - "unicode_decimal": 59611 - }, - { - "icon_id": "8327181", - "name": "stop", - "font_class": "stop", - "unicode": "e60b", - "unicode_decimal": 58891 - }, - { - "icon_id": "714031", - "name": "image", - "font_class": "image", - "unicode": "e62c", - "unicode_decimal": 58924 - }, - { - "icon_id": "23563264", - "name": "SpeakerSlash", - "font_class": "SpeakerSlash", - "unicode": "e661", - "unicode_decimal": 58977 - }, - { - "icon_id": "23563318", - "name": "SpeakerHigh", - "font_class": "SpeakerHigh", - "unicode": "e670", - "unicode_decimal": 58992 - }, - { - "icon_id": "41955357", - "name": " user_voice", - "font_class": "user_voice", - "unicode": "e667", - "unicode_decimal": 58983 - }, - { - "icon_id": "29174196", - "name": "audio", - "font_class": "audio", - "unicode": "e985", - "unicode_decimal": 59781 - }, - { - "icon_id": "40073465", - "name": "hard-disk", - "font_class": "hard-disk", - "unicode": "eb1d", - "unicode_decimal": 60189 - }, - { - "icon_id": "12717507", - "name": "new", - "font_class": "new", - "unicode": "e612", - "unicode_decimal": 58898 - }, - { - "icon_id": "36135335", - "name": "mdp-template-modelscope", - "font_class": "tu2", - "unicode": "e607", - "unicode_decimal": 58887 - }, - { - "icon_id": "10710692", - "name": "robot", - "font_class": "robot", - "unicode": "e634", - "unicode_decimal": 58932 - }, - { - "icon_id": "12070718", - "name": "robot", - "font_class": "robot1", - "unicode": "e602", - "unicode_decimal": 58882 - }, - { - "icon_id": "10791813", - "name": "ai智能", - "font_class": "aizhineng", - "unicode": "e672", - "unicode_decimal": 58994 - }, - { - "icon_id": "19418384", - "name": "copy", - "font_class": "copy", - "unicode": "e720", - "unicode_decimal": 59168 - }, - { - "icon_id": "40757798", - "name": "AI智能", - "font_class": "AIzhineng", - "unicode": "e608", - "unicode_decimal": 58888 - }, - { - "icon_id": "36263088", - "name": "clear", - "font_class": "clear", - "unicode": "e60a", - "unicode_decimal": 58890 - }, - { - "icon_id": "5297059", - "name": "keyboard", - "font_class": "keyboard", - "unicode": "e61b", - "unicode_decimal": 58907 - }, - { - "icon_id": "11539157", - "name": "network error", - "font_class": "networkerror", - "unicode": "e624", - "unicode_decimal": 58916 - }, - { - "icon_id": "14465073", - "name": "external-link", - "font_class": "external-link", - "unicode": "e66b", - "unicode_decimal": 58987 - }, - { - "icon_id": "38465464", - "name": "huggingface", - "font_class": "huggingface", - "unicode": "e7d1", - "unicode_decimal": 59345 - }, - { - "icon_id": "40568411", - "name": "ollama", - "font_class": "ollama", - "unicode": "e601", - "unicode_decimal": 58881 - }, - { - "icon_id": "24341846", - "name": "layout 6-line", - "font_class": "a-layout6-line", - "unicode": "e9ef", - "unicode_decimal": 59887 - }, - { - "icon_id": "31345353", - "name": "a-Layout5", - "font_class": "a-Layout5", - "unicode": "e610", - "unicode_decimal": 58896 - }, - { - "icon_id": "10031665", - "name": "English", - "font_class": "English", - "unicode": "e8b3", - "unicode_decimal": 59571 - }, - { - "icon_id": "9134244", - "name": "chinese", - "font_class": "chinese", - "unicode": "e611", - "unicode_decimal": 58897 - }, - { - "icon_id": "12176725", - "name": "english", - "font_class": "yingguo", - "unicode": "e606", - "unicode_decimal": 58886 - }, - { - "icon_id": "34453176", - "name": "code", - "font_class": "code", - "unicode": "e84f", - "unicode_decimal": 59471 - }, - { - "icon_id": "12579515", - "name": "stop", - "font_class": "stop1", - "unicode": "e783", - "unicode_decimal": 59267 - }, - { - "icon_id": "1842082", - "name": "command", - "font_class": "command", - "unicode": "e600", - "unicode_decimal": 58880 - } - ] -} diff --git a/src/components/icon-font/iconfont/iconfont.ttf b/src/components/icon-font/iconfont/iconfont.ttf deleted file mode 100644 index f29f715f..00000000 Binary files a/src/components/icon-font/iconfont/iconfont.ttf and /dev/null differ diff --git a/src/components/icon-font/iconfont/iconfont.woff b/src/components/icon-font/iconfont/iconfont.woff deleted file mode 100644 index 9ce077cd..00000000 Binary files a/src/components/icon-font/iconfont/iconfont.woff and /dev/null differ diff --git a/src/components/icon-font/iconfont/iconfont.woff2 b/src/components/icon-font/iconfont/iconfont.woff2 deleted file mode 100644 index b67f3b75..00000000 Binary files a/src/components/icon-font/iconfont/iconfont.woff2 and /dev/null differ diff --git a/src/components/icon-font/icons.ts b/src/components/icon-font/icons.ts deleted file mode 100644 index d1678570..00000000 --- a/src/components/icon-font/icons.ts +++ /dev/null @@ -1,71 +0,0 @@ -import IconFont from '@/components/icon-font'; -import { - ApiOutlined, - CopyOutlined, - DeleteOutlined, - DockerOutlined, - DownloadOutlined, - EditOutlined, - ExperimentOutlined, - FileTextOutlined, - KubernetesOutlined, - ProfileOutlined, - RetweetOutlined, - StarOutlined, - ThunderboltOutlined -} from '@ant-design/icons'; -import React from 'react'; - -const icons = { - EditOutlined: React.createElement(EditOutlined), - ExperimentOutlined: React.createElement(ExperimentOutlined), - DeleteOutlined: React.createElement(DeleteOutlined), - ThunderboltOutlined: React.createElement(ThunderboltOutlined), - RetweetOutlined: React.createElement(RetweetOutlined), - DownloadOutlined: React.createElement(DownloadOutlined), - FileTextOutlined: React.createElement(FileTextOutlined), - ApiOutlined: React.createElement(ApiOutlined), - KubernetesOutlined: React.createElement(KubernetesOutlined), - ProfileOutlined: React.createElement(ProfileOutlined), - DockerOutlined: React.createElement(DockerOutlined), - Stop: React.createElement(IconFont, { type: 'icon-stop1' }), - Play: React.createElement(IconFont, { type: 'icon-outline-play' }), - Catalog: React.createElement(IconFont, { type: 'icon-catalog' }), - HF: React.createElement(IconFont, { type: 'icon-huggingface' }), - Ollama: React.createElement(IconFont, { type: 'icon-ollama' }), - ModelScope: React.createElement(IconFont, { type: 'icon-tu2' }), - LocalPath: React.createElement(IconFont, { type: 'icon-hard-disk' }), - Launch: React.createElement(IconFont, { type: 'icon-rocket-launch' }), - Deployment: React.createElement(IconFont, { type: 'icon-rocket-launch1' }), - Docker: React.createElement(IconFont, { type: 'icon-docker' }), - DigitalOcean: React.createElement(IconFont, { type: 'icon-digitalocean' }), - DetailInfo: React.createElement(IconFont, { type: 'icon-detail-info' }), - HuaweiCloud: React.createElement(IconFont, { type: 'icon-huaweicloud' }), - AliCloud: React.createElement(IconFont, { type: 'icon-alicloud' }), - TencentCloud: React.createElement(IconFont, { type: 'icon-tencentcloud' }), - Nvidia: React.createElement(IconFont, { type: 'icon-nvidia' }), - Ascend: React.createElement(IconFont, { type: 'icon-ascend' }), - Catalog1: React.createElement(IconFont, { type: 'icon-catalog1' }), - AMD: React.createElement(IconFont, { type: 'icon-amd' }), - KubernetesFilled: React.createElement(IconFont, { type: 'icon-k8s-filled' }), - EditContent: React.createElement(IconFont, { type: 'icon-edit-content' }), - Yaml: React.createElement(IconFont, { type: 'icon-code_block' }), - Version: React.createElement(IconFont, { type: 'icon-version' }), - Parameter: React.createElement(IconFont, { type: 'icon-parameters' }), - Private: React.createElement(IconFont, { type: 'icon-private' }), - AWS: React.createElement(IconFont, { type: 'icon-aws' }), - LockOpenRight: React.createElement(IconFont, { - type: 'icon-lock_open_right' - }), - LockPerson: React.createElement(IconFont, { type: 'icon-lock_person' }), - LockOpen: React.createElement(IconFont, { type: 'icon-lock_open' }), - Permission: React.createElement(IconFont, { type: 'icon-permission' }), - CaptivePortal: React.createElement(IconFont, { type: 'icon-captive_portal' }), - StarOutlined: React.createElement(StarOutlined), - Charger: React.createElement(IconFont, { type: 'icon-charger' }), - Disabled: React.createElement(IconFont, { type: 'icon-disabled' }), - CopyOutlined: React.createElement(CopyOutlined), - Metrics: React.createElement(IconFont, { type: 'icon-metrics' }) -}; - -export default icons; diff --git a/src/components/icon-font/index.tsx b/src/components/icon-font/index.tsx deleted file mode 100644 index 08df0a0b..00000000 --- a/src/components/icon-font/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { createFromIconfontCN } from '@ant-design/icons'; -// import './iconfont/iconfont.js'; - -const IconFont = createFromIconfontCN({ - scriptUrl: '//at.alicdn.com/t/c/font_4613488_mk9rqojjoqk.js' -}); - -export default IconFont; diff --git a/src/components/image-editor/extract-image-colors.ts b/src/components/image-editor/extract-image-colors.ts deleted file mode 100644 index 15d136f1..00000000 --- a/src/components/image-editor/extract-image-colors.ts +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Creates a canvas element and its rendering context. - * @param {number} width - Canvas width. - * @param {number} height - Canvas height. - * @returns {{ canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D }} - The created canvas and context. - */ -function createCanvas( - width: number, - height: number -): { canvas: HTMLCanvasElement; ctx: CanvasRenderingContext2D } { - const canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; - return { canvas, ctx: canvas.getContext('2d')! }; -} - -/** - * Checks if a pixel is white. - * @param {Uint8ClampedArray} pixels - The image pixel data. - * @param {number} x - The pixel's X coordinate. - * @param {number} y - The pixel's Y coordinate. - * @param {number} width - The image width. - * @returns {boolean} - Whether the pixel is white. - */ -function isWhite( - pixels: Uint8ClampedArray, - x: number, - y: number, - width: number -): boolean { - let index = (y * width + x) * 4; - return ( - pixels[index] === 255 && - pixels[index + 1] === 255 && - pixels[index + 2] === 255 - ); -} - -/** - * Performs a flood fill to find all connected white pixels. - * @param {Uint8ClampedArray} pixels - The image pixel data. - * @param {number} width - The image width. - * @param {number} height - The image height. - * @param {number} x - The starting X coordinate. - * @param {number} y - The starting Y coordinate. - * @param {boolean[][]} visited - A 2D array to track visited pixels. - * @param {Array<{ x: number, y: number }>} block - The list of coordinates forming a white block. - */ -function floodFill( - pixels: Uint8ClampedArray, - width: number, - height: number, - x: number, - y: number, - visited: boolean[][], - block: Array<{ x: number; y: number }> -): void { - let stack: Array<[number, number]> = [[x, y]]; - let directions: Array<[number, number]> = [ - [1, 0], - [-1, 0], - [0, 1], - [0, -1], // 4-directional search (can be extended to 8-directional) - [1, 1], - [-1, -1], - [1, -1], - [-1, 1] // Diagonal directions - ]; - - while (stack.length) { - let [cx, cy] = stack.pop()!; - if ( - cx < 0 || - cy < 0 || - cx >= width || - cy >= height || - visited[cy][cx] || - !isWhite(pixels, cx, cy, width) - ) { - continue; - } - - visited[cy][cx] = true; - block.push({ x: cx, y: cy }); - - directions.forEach(([dx, dy]) => stack.push([cx + dx, cy + dy])); - } -} - -/** - * Extracts all white blocks from an image. - * @param {ImageData} imageData - The image pixel data. - * @returns {Array>} - List of white blocks, each containing pixel coordinates. - */ -function getWhiteBlocks( - imageData: ImageData -): Array> { - const { data, width, height } = imageData; - let visited: boolean[][] = Array.from({ length: height }, () => - new Array(width).fill(false) - ); - let whiteBlocks: Array> = []; - - for (let y = 0; y < height; y++) { - for (let x = 0; x < width; x++) { - if (isWhite(data, x, y, width) && !visited[y][x]) { - let block: Array<{ x: number; y: number }> = []; - floodFill(data, width, height, x, y, visited, block); - whiteBlocks.push(block); - } - } - } - return whiteBlocks; -} - -/** - * Loads an image from a file. - * @param {File} file - The image file. - * @returns {Promise} - The loaded image element. - */ -function loadImage(file: string): Promise { - return new Promise((resolve, reject) => { - const img = new Image(); - img.src = file; - img.onload = () => resolve(img); - img.onerror = () => reject(new Error('Image loading failed')); - }); -} - -/** - * Processes the image file and extracts white blocks. - * @param {File} file - The uploaded image file. - * @returns {Promise>>} - List of white blocks with pixel coordinates. - */ -async function processImage( - file: string -): Promise>> { - const img = await loadImage(file); - const { canvas, ctx } = createCanvas(img.width, img.height); - ctx.drawImage(img, 0, 0); - - const imageData = ctx.getImageData(0, 0, img.width, img.height); - const whiteBlocks = getWhiteBlocks(imageData); - - URL.revokeObjectURL(img.src); - return whiteBlocks; -} - -export { processImage }; diff --git a/src/components/image-editor/hooks/use-drawing.ts b/src/components/image-editor/hooks/use-drawing.ts deleted file mode 100644 index 1eace8a9..00000000 --- a/src/components/image-editor/hooks/use-drawing.ts +++ /dev/null @@ -1,437 +0,0 @@ -import _ from 'lodash'; -import React, { useCallback, useMemo, useRef } from 'react'; - -type Point = { x: number; y: number; lineWidth: number }; -type Stroke = Point[]; -const COLOR = 'rgba(0, 0, 255, 0.3)'; - -export default function useDrawing(props: { - isDisabled?: boolean; - invertMask: boolean; - maskUpload?: any[]; - lineWidth: number; - translatePos: { current: { x: number; y: number } }; - onSave: (imageData: { mask: string | null; img: string }) => void; -}) { - const { - isDisabled, - invertMask, - maskUpload, - lineWidth, - translatePos, - onSave - } = props; - const mouseDownState = useRef(false); - const canvasRef = useRef(null); - const overlayCanvasRef = useRef(null); - const offscreenCanvasRef = useRef(null); - const currentStroke = useRef([]); - const strokesRef = useRef([]); - const isDrawing = useRef(false); - const cursorRef = useRef(null); - const autoScale = useRef(1); - const baseScale = useRef(1); - const contentPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); - const maskStorkeRef = useRef([]); - const isLoadingMaskRef = useRef(false); - - const disabled = useMemo(() => { - return isDisabled || invertMask || !!maskUpload?.length; - }, [isDisabled, invertMask, maskUpload]); - - const setStrokes = (strokes: Stroke[]) => { - strokesRef.current = strokes; - }; - - const setMaskStrokes = (strokes: Stroke[]) => { - maskStorkeRef.current = strokes; - }; - - const inpaintArea = useCallback( - (data: Uint8ClampedArray) => { - for (let i = 0; i < data.length; i += 4) { - const alpha = data[i + 3]; - if (alpha > 0) { - data[i] = 255; // Red - data[i + 1] = 255; // Green - data[i + 2] = 255; // Blue - data[i + 3] = 255; // Alpha - } - } - }, - [] - ); - - const generateImage = useCallback(() => { - const canvas = canvasRef.current!; - return canvas.toDataURL('image/png'); - }, []); - - const generateMask = useCallback(() => { - if (strokesRef.current.length === 0 && maskStorkeRef.current.length === 0) { - return null; - } - const overlayCanvas = overlayCanvasRef.current!; - const maskCanvas = document.createElement('canvas'); - maskCanvas.width = overlayCanvas.width; - maskCanvas.height = overlayCanvas.height; - const maskCtx = maskCanvas.getContext('2d')!; - const overlayCtx = overlayCanvas.getContext('2d')!; - - const imageData = overlayCtx.getImageData( - 0, - 0, - overlayCanvas.width, - overlayCanvas.height - ); - const data = imageData.data; - - inpaintArea(data); - - maskCtx.putImageData(imageData, 0, 0); - - maskCtx.globalCompositeOperation = 'destination-over'; - maskCtx.fillStyle = 'black'; - maskCtx.fillRect(0, 0, maskCanvas.width, maskCanvas.height); - - return maskCanvas.toDataURL('image/png'); - }, []); - - const saveImage = () => { - const mask = generateMask(); - const img = generateImage(); - onSave({ mask, img }); - }; - - const creatOffscreenCanvas = useCallback(() => { - if (!offscreenCanvasRef.current) { - offscreenCanvasRef.current = document.createElement('canvas'); - } - }, []); - - const setTransform = useCallback(() => { - creatOffscreenCanvas(); - const ctx = canvasRef.current?.getContext('2d'); - const overlayCtx = overlayCanvasRef.current?.getContext('2d'); - const offCtx = offscreenCanvasRef.current?.getContext('2d'); - - if (!ctx || !overlayCtx) return; - - ctx!.resetTransform(); - overlayCtx!.resetTransform(); - offCtx!.resetTransform(); - - const { current: scale } = autoScale; - const { x: translateX, y: translateY } = translatePos.current; - ctx!.setTransform(scale, 0, 0, scale, translateX, translateY); - overlayCtx!.setTransform(scale, 0, 0, scale, translateX, translateY); - offCtx!.setTransform(scale, 0, 0, scale, translateX, translateY); - }, []); - - const getTransformedPoint = (offsetX: number, offsetY: number) => { - const { current: scale } = autoScale; - console.log('lineWidth:----------', lineWidth, autoScale.current); - - const { x: translateX, y: translateY } = translatePos.current; - - const transformedX = (offsetX - translateX) / scale; - const transformedY = (offsetY - translateY) / scale; - - return { - x: transformedX, - y: transformedY - }; - }; - - const getTransformLineWidth = (w = 1) => { - console.log('lineWidth:', lineWidth, autoScale.current); - const width = w || lineWidth; - return width / autoScale.current; - }; - - const drawLine = useCallback( - ( - ctx: CanvasRenderingContext2D, - point: Point, - options: { - lineWidth: number; - color: string; - compositeOperation: 'source-over' | 'destination-out'; - } - ) => { - const { lineWidth, color, compositeOperation } = options; - - ctx.lineWidth = getTransformLineWidth(lineWidth); - ctx.lineCap = 'round'; - ctx.lineJoin = 'round'; - ctx.globalCompositeOperation = compositeOperation; - - const { x, y } = getTransformedPoint(point.x, point.y); - - ctx.lineTo(x, y); - if (compositeOperation === 'source-over') { - ctx.strokeStyle = color; - } - ctx.stroke(); - }, - [getTransformLineWidth] - ); - - const drawStroke = useCallback( - ( - ctx: CanvasRenderingContext2D, - stroke: Stroke | Point[], - options: { - lineWidth?: number; - color: string; - compositeOperation: 'source-over' | 'destination-out'; - } - ) => { - const { color, compositeOperation } = options; - ctx.lineCap = 'round'; - ctx.lineJoin = 'round'; - ctx.globalCompositeOperation = compositeOperation; - ctx.save(); - - ctx.beginPath(); - - stroke.forEach((point, i) => { - const { x, y } = getTransformedPoint(point.x, point.y); - ctx.lineWidth = getTransformLineWidth(point.lineWidth); - if (i === 0) { - ctx.moveTo(x, y); - } else { - ctx.lineTo(x, y); - } - }); - if (compositeOperation === 'source-over') { - ctx.strokeStyle = color; - } - ctx.stroke(); - ctx.restore(); - }, - [getTransformLineWidth, getTransformedPoint] - ); - - const draw = (e: React.MouseEvent) => { - if (disabled) { - return; - } - console.log( - 'Drawing:', - isDrawing.current, - currentStroke.current, - strokesRef.current - ); - if (!isDrawing.current || !mouseDownState.current) return; - - const { offsetX, offsetY } = e.nativeEvent; - const currentX = offsetX; - const currentY = offsetY; - console.log('currentStroke:', currentStroke.current); - currentStroke.current.push({ - x: currentX, - y: currentY, - lineWidth - }); - - const ctx = overlayCanvasRef.current!.getContext('2d'); - - ctx!.save(); - - drawLine( - ctx!, - { x: currentX, y: currentY, lineWidth }, - { lineWidth, color: COLOR, compositeOperation: 'destination-out' } - ); - drawLine( - ctx!, - { x: currentX, y: currentY, lineWidth }, - { lineWidth, color: COLOR, compositeOperation: 'source-over' } - ); - - ctx!.restore(); - }; - - const startDrawing = (e: React.MouseEvent) => { - if (disabled) { - return; - } - - isDrawing.current = true; - - currentStroke.current = []; - const { offsetX, offsetY } = e.nativeEvent; - - const currentX = offsetX; - const currentY = offsetY; - - currentStroke.current.push({ - x: currentX, - y: currentY, - lineWidth - }); - - const ctx = overlayCanvasRef.current!.getContext('2d'); - setTransform(); - const { x, y } = getTransformedPoint(currentX, currentY); - ctx!.beginPath(); - ctx!.moveTo(x, y); - - draw(e); - }; - - const endDrawing = (e: React.MouseEvent) => { - if (disabled) { - return; - } - if (!isDrawing.current) { - return; - } - - console.log('End Drawing:', e); - - isDrawing.current = false; - - strokesRef.current.push(_.cloneDeep(currentStroke.current)); - - currentStroke.current = []; - - saveImage(); - }; - - const handleMouseMove = (e: React.MouseEvent) => { - if (disabled) { - return; - } - overlayCanvasRef.current!.style.cursor = 'none'; - cursorRef.current!.style.display = 'block'; - cursorRef.current!.style.top = `${e.clientY - (lineWidth / 2) * autoScale.current}px`; - cursorRef.current!.style.left = `${e.clientX - (lineWidth / 2) * autoScale.current}px`; - }; - - const handleMouseLeave = () => { - if (disabled) { - return; - } - isDrawing.current = false; - overlayCanvasRef.current!.style.cursor = 'default'; - cursorRef.current!.style.display = 'none'; - }; - - const handleMouseEnter = (e: React.MouseEvent) => { - console.log('mouse enter:', mouseDownState.current); - if (disabled) { - overlayCanvasRef.current!.style.cursor = 'default'; - return; - } - // if (mouseDownState.current) { - // isDrawing.current = true; - // } - overlayCanvasRef.current!.style.cursor = 'none'; - cursorRef.current!.style.display = 'block'; - cursorRef.current!.style.top = `${e.clientY - (lineWidth / 2) * autoScale.current}px`; - cursorRef.current!.style.left = `${e.clientX - (lineWidth / 2) * autoScale.current}px`; - }; - - const clearOverlayCanvas = useCallback(() => { - const ctx = overlayCanvasRef.current!.getContext('2d'); - const offCtx = offscreenCanvasRef.current?.getContext('2d'); - - offCtx!.resetTransform(); - ctx!.resetTransform(); - ctx!.clearRect( - 0, - 0, - overlayCanvasRef.current!.width, - overlayCanvasRef.current!.height - ); - offCtx!.clearRect( - 0, - 0, - overlayCanvasRef.current!.width, - overlayCanvasRef.current!.height - ); - }, []); - - const clearCanvas = useCallback(() => { - const canvas = canvasRef.current!; - const ctx = canvasRef.current!.getContext('2d'); - const offCtx = offscreenCanvasRef.current?.getContext('2d'); - ctx!.resetTransform(); - ctx!.clearRect(0, 0, canvas.width, canvas.height); - - offCtx!.resetTransform(); - offCtx!.clearRect(0, 0, canvas.width, canvas.height); - }, []); - - const resetCanvas = useCallback(() => { - const canvas = canvasRef.current!; - const overlayCanvas = overlayCanvasRef.current!; - const offscreenCanvas = offscreenCanvasRef.current!; - const ctx = canvas.getContext('2d'); - const overlayCtx = overlayCanvas.getContext('2d'); - const offCtx = offscreenCanvasRef.current?.getContext('2d'); - - autoScale.current = 1; - baseScale.current = 1; - translatePos.current = { x: 0, y: 0 }; - contentPos.current = { x: 0, y: 0 }; - - canvas.style.transform = 'scale(1)'; - overlayCanvas.style.transform = 'scale(1)'; - offscreenCanvas.style.transform = 'scale(1)'; - - cursorRef.current!.style.width = `${lineWidth}px`; - cursorRef.current!.style.height = `${lineWidth}px`; - - ctx!.resetTransform(); - overlayCtx!.resetTransform(); - offCtx!.resetTransform(); - }, []); - - const fitView = () => { - resetCanvas(); - autoScale.current = baseScale.current; - translatePos.current = { x: 0, y: 0 }; - setTransform(); - overlayCanvasRef.current!.style.transform = `scale(${autoScale.current})`; - canvasRef.current!.style.transform = `scale(${autoScale.current})`; - offscreenCanvasRef.current!.style.transform = `scale(${autoScale.current})`; - }; - - return { - canvasRef, - overlayCanvasRef, - offscreenCanvasRef, - cursorRef, - strokesRef, - currentStroke, - isDrawing, - mouseDownState, - autoScale, - baseScale, - maskStorkeRef, - isLoadingMaskRef, - creatOffscreenCanvas, - setMaskStrokes, - fitView, - setStrokes, - resetCanvas, - draw, - getTransformLineWidth, - getTransformedPoint, - drawStroke, - startDrawing, - endDrawing, - handleMouseMove, - handleMouseLeave, - handleMouseEnter, - saveImage, - generateMask, - generateImage, - setTransform, - clearOverlayCanvas, - clearCanvas - }; -} diff --git a/src/components/image-editor/hooks/use-zoom.ts b/src/components/image-editor/hooks/use-zoom.ts deleted file mode 100644 index bfe9c3a0..00000000 --- a/src/components/image-editor/hooks/use-zoom.ts +++ /dev/null @@ -1,128 +0,0 @@ -import _ from 'lodash'; -import React, { MutableRefObject, useState } from 'react'; - -export default function useZoom(props: { - overlayCanvasRef: any; - canvasRef: any; - offscreenCanvasRef: any; - cursorRef: any; - lineWidth: number; - autoScale: MutableRefObject; - baseScale: MutableRefObject; - translatePos: MutableRefObject<{ x: number; y: number }>; - isLoadingMaskRef: MutableRefObject; -}) { - const MIN_SCALE = 0.2; - const MAX_SCALE = 8; - const ZOOM_SPEED = 0.1; - const { - overlayCanvasRef, - canvasRef, - offscreenCanvasRef, - cursorRef, - lineWidth, - translatePos, - autoScale, - baseScale, - isLoadingMaskRef - } = props; - - const [activeScale, setActiveScale] = useState(1); - - const setCanvasTransformOrigin = (e: React.MouseEvent) => { - if (autoScale.current <= MIN_SCALE) { - return; - } - - if (autoScale.current >= MAX_SCALE) { - return; - } - - const rect = overlayCanvasRef.current!.getBoundingClientRect(); - const mouseX = e.clientX - rect.left; - const mouseY = e.clientY - rect.top; - - const originX = mouseX / rect.width; - const originY = mouseY / rect.height; - - overlayCanvasRef.current!.style.transformOrigin = `${originX * 100}% ${originY * 100}%`; - canvasRef.current!.style.transformOrigin = `${originX * 100}% ${originY * 100}%`; - offscreenCanvasRef.current!.style.transformOrigin = `${originX * 100}% ${originY * 100}%`; - }; - - const updateZoom = (scaleChange: number, mouseX: number, mouseY: number) => { - const newScale = _.round(autoScale.current + scaleChange, 2); - - if (newScale < MIN_SCALE || newScale > MAX_SCALE) return; - - const { current: oldScale } = autoScale; - const { x: oldTranslateX, y: oldTranslateY } = translatePos.current; - - const centerX = (mouseX - oldTranslateX) / oldScale; - const centerY = (mouseY - oldTranslateY) / oldScale; - - autoScale.current = newScale; - - const newTranslateX = mouseX - centerX * newScale; - const newTranslateY = mouseY - centerY * newScale; - - translatePos.current = { x: newTranslateX, y: newTranslateY }; - }; - - const applyCanvasTransform = () => { - const scale = autoScale.current; - const transform = `scale(${scale})`; - - overlayCanvasRef.current!.style.transform = transform; - canvasRef.current!.style.transform = transform; - offscreenCanvasRef.current!.style.transform = transform; - }; - - const handleZoom = (event: React.WheelEvent) => { - const scaleChange = event.deltaY > 0 ? -ZOOM_SPEED : ZOOM_SPEED; - - // current mouse position - const canvas = overlayCanvasRef.current!; - const rect = canvas.getBoundingClientRect(); - - const mouseX = event.clientX - rect.left; - const mouseY = event.clientY - rect.top; - applyCanvasTransform(); - - setCanvasTransformOrigin(event); - updateZoom(scaleChange, mouseX, mouseY); - }; - - const updateCursorSize = () => { - cursorRef.current!.style.width = `${lineWidth * autoScale.current}px`; - cursorRef.current!.style.height = `${lineWidth * autoScale.current}px`; - }; - - const updateCursorPosOnZoom = (e: any) => { - cursorRef.current!.style.top = `${e.clientY - (lineWidth / 2) * autoScale.current}px`; - cursorRef.current!.style.left = `${e.clientX - (lineWidth / 2) * autoScale.current}px`; - }; - - const handleOnWheel = (event: any) => { - if (isLoadingMaskRef.current) { - return; - } - // stop - handleZoom(event); - updateCursorSize(); - updateCursorPosOnZoom(event); - setActiveScale(autoScale.current); - }; - - const throttleHandleOnWheel = _.throttle((event: any) => { - handleOnWheel(event); - }, 16); - - return { - handleOnWheel: handleOnWheel, - setActiveScale, - activeScale, - autoScale, - baseScale - }; -} diff --git a/src/components/image-editor/index.less b/src/components/image-editor/index.less deleted file mode 100644 index 68f663f8..00000000 --- a/src/components/image-editor/index.less +++ /dev/null @@ -1,39 +0,0 @@ -.editor-wrapper { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - - .tools { - margin-bottom: 10px; - display: flex; - gap: 10px; - } - - .editor-content { - display: flex; - justify-content: center; - align-items: center; - overflow: hidden; - } - - .overlay-canvas:hover { - cursor: none !important; - } - - .overlay-canvas.overlay-canvas--disabled:hover { - cursor: default !important; - } - - .upload-mask { - &:hover { - .close-btn { - display: block; - } - } - } - - .close-btn { - display: none; - } -} diff --git a/src/components/image-editor/index.tsx b/src/components/image-editor/index.tsx deleted file mode 100644 index d68d664f..00000000 --- a/src/components/image-editor/index.tsx +++ /dev/null @@ -1,645 +0,0 @@ -import { Spin } from 'antd'; -import classNames from 'classnames'; -import dayjs from 'dayjs'; -import React, { - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useMemo, - useRef, - useState -} from 'react'; -import styled from 'styled-components'; -import useDrawing from './hooks/use-drawing'; -import useZoom from './hooks/use-zoom'; -import './index.less'; -import { ImageActionsBar, ToolsBar } from './tools-bar'; - -const LoadWrapper = styled.div<{ width?: number; height?: number }>` - position: absolute; - top: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; - height: 100%; - width: ${(props) => `${props.width}px` || '100%'}; - z-index: 100; -`; - -const Loading = (props: { width: number; height: number }) => { - const { width, height } = props; - return ( - - - - ); -}; - -type Point = { x: number; y: number; lineWidth: number }; -type Stroke = Point[]; - -type CanvasImageEditorProps = { - ref?: any; - loading: boolean; - imageSrc: string; - disabled?: boolean; - imguid: string | number; - maskUpload?: any[]; - clearUploadMask?: () => void; - onSave: (imageData: { mask: string | null; img: string }) => void; - onScaleImageSize?: (data: { width: number; height: number }) => void; - handleUpdateImageList: (fileList: any[]) => void; - handleUpdateMaskList: (fileList: any[]) => void; - uploadButton?: React.ReactNode; - accept?: string; - imageStatus: { - isOriginal: boolean; - isResetNeeded: boolean; - width: number; - height: number; - }; -}; - -const COLOR = 'rgba(0, 0, 255, 0.3)'; - -const CanvasImageEditor: React.FC = forwardRef( - ( - { - loading, - imageSrc, - disabled: isDisabled, - imageStatus, - maskUpload, - accept, - onSave, - onScaleImageSize, - handleUpdateImageList, - handleUpdateMaskList - }, - ref - ) => { - const invertWorkerRef = useRef(null); - const loadMaksWorkerRef = useRef(null); - const containerRef = useRef(null); - const [lineWidth, setLineWidth] = useState(60); - const translatePos = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); - const negativeMaskRef = useRef(false); - const [invertMask, setInvertMask] = useState(false); - const timer = useRef(null); - const [loadingSize, setLoadingSize] = useState({ - width: 0, - height: 0, - loading: false - }); - - const { - canvasRef, - overlayCanvasRef, - offscreenCanvasRef, - cursorRef, - strokesRef, - currentStroke, - mouseDownState, - autoScale, - baseScale, - maskStorkeRef, - isLoadingMaskRef, - setMaskStrokes, - draw, - drawStroke, - startDrawing, - endDrawing, - handleMouseMove, - handleMouseLeave, - handleMouseEnter, - saveImage, - resetCanvas, - creatOffscreenCanvas, - generateMask, - getTransformLineWidth, - getTransformedPoint, - setStrokes, - setTransform, - clearOverlayCanvas, - clearCanvas, - fitView - } = useDrawing({ - lineWidth: lineWidth, - translatePos: translatePos, - isDisabled: isDisabled, - invertMask, - maskUpload, - onSave: onSave - }); - - const { handleOnWheel, setActiveScale, activeScale } = useZoom({ - overlayCanvasRef, - canvasRef, - offscreenCanvasRef, - cursorRef, - lineWidth, - translatePos, - autoScale, - baseScale, - isLoadingMaskRef - }); - - const disabled = useMemo(() => { - return isDisabled || invertMask || !!maskUpload?.length; - }, [isDisabled, invertMask, maskUpload]); - - // update the canvas size - const updateCanvasSize = useCallback(() => { - const canvas = canvasRef.current!; - const overlayCanvas = overlayCanvasRef.current!; - const offscreenCanvas = offscreenCanvasRef.current!; - - overlayCanvas.width = canvas.width; - overlayCanvas.height = canvas.height; - offscreenCanvas.width = canvas.width; - offscreenCanvas.height = canvas.height; - }, []); - - const downloadMask = useCallback(() => { - const mask = generateMask(); - - const link = document.createElement('a'); - link.download = `mask_${dayjs().format('YYYYMMDDHHmmss')}.png`; - link.href = mask || ''; - link.click(); - }, [generateMask]); - - const onReset = useCallback(() => { - clearOverlayCanvas(); - setStrokes([]); - setMaskStrokes([]); - saveImage(); - currentStroke.current = []; - console.log('Resetting strokes', currentStroke.current); - }, []); - - const loadMaskPixs = (maskStrokes: Stroke[], mainStrokes?: Stroke[]) => { - try { - if (!maskStrokes.length && !mainStrokes?.length) { - return; - } - - isLoadingMaskRef.current = true; - - const offscreenCanvas = new OffscreenCanvas( - overlayCanvasRef.current!.width, - overlayCanvasRef.current!.height - ); - - if (!loadMaksWorkerRef.current) { - loadMaksWorkerRef.current = new Worker( - new URL('./offscreen-worker.ts', import.meta.url), - { - type: 'module' - } - ); - } - - loadMaksWorkerRef.current!.onmessage = (event: any) => { - if (event.data.type === 'done' && event.data.imageData) { - console.log('load mask done'); - // draw the data to the overlay canvas - const ctx = overlayCanvasRef.current!.getContext('2d')!; - ctx.putImageData(event.data.imageData, 0, 0); - - isLoadingMaskRef.current = false; - saveImage(); - } - }; - - // send offscreen canvas to worker - loadMaksWorkerRef.current?.postMessage( - { canvas: offscreenCanvas, type: 'init' }, - [offscreenCanvas] - ); - - // send draw data to worker - loadMaksWorkerRef.current?.postMessage({ - type: 'draw', - maskStrokes: maskStrokes, - strokes: mainStrokes || [] - }); - } catch (error) { - console.log('error---', error); - } - }; - - const redrawStrokes = async (strokes: Stroke[]) => { - if (!strokes.length && !maskStorkeRef.current.length) { - clearOverlayCanvas(); - return; - } - - loadMaskPixs(maskStorkeRef.current, strokes); - }; - - const undo = useCallback(() => { - if ( - strokesRef.current.length === 0 && - maskStorkeRef.current.length === 0 - ) { - clearOverlayCanvas(); - return; - } - - const lastlength = strokesRef.current.length; - - const newStrokes = strokesRef.current.slice(0, -1); - setStrokes(newStrokes); - - if ( - !newStrokes.length && - lastlength === 0 && - maskStorkeRef.current.length - ) { - setMaskStrokes([]); - } - clearTimeout(timer.current); - timer.current = setTimeout(() => { - redrawStrokes(newStrokes); - }, 100); - }, []); - - const downloadOriginImage = () => { - const canvas = canvasRef.current!; - const link = document.createElement('a'); - link.download = `image_${dayjs().format('YYYYMMDDHHmmss')}.png`; - link.href = canvas.toDataURL('image/png'); - link.click(); - link.remove(); - }; - - const downloadNewImage = () => { - if (!imageSrc) return; - - const img = new Image(); - img.src = imageSrc; - img.onload = () => { - const canvas = document.createElement('canvas'); - canvas.width = imageStatus.width; - canvas.height = imageStatus.height; - - const ctx = canvas.getContext('2d')!; - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - - const url = canvas.toDataURL('image/png'); - const filename = `${canvas.width}x${canvas.height}_${dayjs().format('YYYYMMDDHHmmss')}.png`; - - const link = document.createElement('a'); - link.href = url; - link.download = filename; - document.body.appendChild(link); - link.click(); - link.remove(); - }; - }; - - const download = () => { - if (imageStatus.isOriginal) { - downloadOriginImage(); - } else { - downloadNewImage(); - } - }; - - const drawImage = useCallback(async () => { - if (!containerRef.current || !canvasRef.current) return; - return new Promise((resolve) => { - const img = new Image(); - img.src = imageSrc; - img.onload = () => { - const canvas = canvasRef.current!; - const ctx = canvas!.getContext('2d'); - const container = containerRef.current; - baseScale.current = Math.min( - container!.offsetWidth / img.width, - container!.offsetHeight / img.height, - 1 - ); - - // if need to fit the image to the container, show * baseScale.current - canvas!.width = img.width; - canvas!.height = img.height; - - // fit the image to the container - autoScale.current = 1; - creatOffscreenCanvas(); - updateCanvasSize(); - clearCanvas(); - - ctx!.drawImage(img, 0, 0, canvas!.width, canvas!.height); - resolve(); - }; - }); - }, [imageSrc]); - - const invertPainting = (isChecked: boolean) => { - const ctx = overlayCanvasRef.current!.getContext('2d'); - - if (!ctx) return; - - if (isChecked) { - const canvasWidth = overlayCanvasRef.current!.width; - const canvasHeight = overlayCanvasRef.current!.height; - - clearOverlayCanvas(); - - const offscreenCanvas = new OffscreenCanvas( - overlayCanvasRef.current!.width, - overlayCanvasRef.current!.height - ); - - if (!invertWorkerRef.current) { - invertWorkerRef.current = new Worker( - new URL('./invert-worker.ts', import.meta.url), - { - type: 'module' - } - ); - } - - invertWorkerRef.current.onmessage = (event: any) => { - if (event.data.type === 'done' && event.data.imageData) { - // draw the data to the overlay canvas - const ctx = overlayCanvasRef.current!.getContext('2d')!; - ctx.putImageData(event.data.imageData, 0, 0); - - isLoadingMaskRef.current = false; - saveImage(); - } - }; - - // send offscreen canvas to worker - invertWorkerRef.current?.postMessage( - { canvas: offscreenCanvas, type: 'init' }, - [offscreenCanvas] - ); - - // send draw data to worker - const imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight); - invertWorkerRef.current?.postMessage({ - type: 'draw', - width: imageData.width, - height: imageData.height, - strokes: strokesRef.current, - maskStrokes: maskStorkeRef.current - }); - } else { - redrawStrokes(strokesRef.current); - } - }; - - const updateCursorSize = () => { - cursorRef.current!.style.width = `${lineWidth * autoScale.current}px`; - cursorRef.current!.style.height = `${lineWidth * autoScale.current}px`; - }; - - const initializeImage = useCallback(async () => { - await drawImage(); - onScaleImageSize?.({ - width: canvasRef.current!.width, - height: canvasRef.current!.height - }); - - if (imageStatus.isResetNeeded) { - onReset(); - resetCanvas(); - } else if ( - (strokesRef.current.length || maskStorkeRef.current.length) && - imageStatus.isOriginal && - !negativeMaskRef.current - ) { - redrawStrokes(strokesRef.current); - } else if ( - (strokesRef.current.length || maskStorkeRef.current.length) && - imageStatus.isOriginal && - negativeMaskRef.current - ) { - invertPainting(true); - } - console.log('Image status:', imageStatus, negativeMaskRef.current); - - updateCursorSize(); - }, [drawImage, imageStatus.isOriginal, imageStatus.isResetNeeded]); - - const handleFitView = () => { - fitView(); - setActiveScale(autoScale.current); - updateCursorSize(); - }; - - const handleBrushSizeChange = (value: number) => { - setLineWidth(value); - cursorRef.current!.style.width = `${value}px`; - cursorRef.current!.style.height = `${value}px`; - }; - - const handleOnChangeMask = (e: any) => { - negativeMaskRef.current = e.target.checked; - invertPainting(e.target.checked); - setInvertMask(e.target.checked); - }; - - useEffect(() => { - initializeImage(); - }, [initializeImage]); - - useEffect(() => { - const handleUndoShortcut = (e: KeyboardEvent) => { - if ( - (e.ctrlKey || e.metaKey) && - e.key === 'z' && - !negativeMaskRef.current - ) { - undo(); - } - }; - window.addEventListener('keydown', handleUndoShortcut); - - return () => { - window.removeEventListener('keydown', handleUndoShortcut); - }; - }, []); - - useEffect(() => { - const handleMouseDown = (e: MouseEvent) => { - mouseDownState.current = true; - }; - - const handleMouseUp = (e: MouseEvent) => { - mouseDownState.current = false; - }; - - // mouse down - window.addEventListener('mousedown', handleMouseDown); - - // mouse up - window.addEventListener('mouseup', handleMouseUp); - return () => { - clearTimeout(timer.current); - - window.removeEventListener('mousedown', handleMouseDown); - window.removeEventListener('mouseup', handleMouseUp); - }; - }, []); - - const handleDeleteMask = () => { - setInvertMask(false); - redrawStrokes(strokesRef.current); - saveImage(); - }; - - useImperativeHandle(ref, () => ({ - clearMask: handleDeleteMask, - loadMaskPixs: async function (strokes: Stroke[]) { - setMaskStrokes(strokes); - setStrokes([]); - setTransform(); - clearOverlayCanvas(); - loadMaskPixs(strokes); - } - })); - - useEffect(() => { - invertWorkerRef.current = new Worker( - new URL('./invert-worker.ts', import.meta.url), - { - type: 'module' - } - ); - - loadMaksWorkerRef.current = new Worker( - new URL('./offscreen-worker.ts', import.meta.url), - { - type: 'module' - } - ); - - return () => { - invertWorkerRef.current?.terminate(); - loadMaksWorkerRef.current?.terminate(); - }; - }, []); - - useEffect(() => { - if (maskUpload?.length) { - // clear the overlay canvas - clearOverlayCanvas(); - } - }, [maskUpload]); - - useEffect(() => { - if (disabled && cursorRef.current) { - cursorRef.current!.style.display = 'none'; - } - }, [disabled]); - - return ( -
-
- - - -
-
- {loadingSize.loading && ( - - )} - - { - if (isLoadingMaskRef.current) { - return; - } - mouseDownState.current = true; - startDrawing(event); - }} - onMouseUp={(event) => { - if (isLoadingMaskRef.current) { - return; - } - mouseDownState.current = false; - endDrawing(event); - }} - onMouseEnter={handleMouseEnter} - onWheel={handleOnWheel} - onMouseMove={(e) => { - if (isLoadingMaskRef.current) { - return; - } - handleMouseMove(e); - draw(e); - }} - onMouseLeave={(e) => { - if (isLoadingMaskRef.current) { - return; - } - endDrawing(e); - handleMouseLeave(); - }} - /> -
-
-
- ); - } -); - -export default React.memo(CanvasImageEditor); diff --git a/src/components/image-editor/invert-worker.ts b/src/components/image-editor/invert-worker.ts deleted file mode 100644 index 6c95eeaf..00000000 --- a/src/components/image-editor/invert-worker.ts +++ /dev/null @@ -1,54 +0,0 @@ -/// - -let offscreenCanvas: OffscreenCanvas; -let ctx: OffscreenCanvasRenderingContext2D; - -const COLOR = 'rgba(0, 0, 255, 0.3)'; - -type Point = { x: number; y: number; lineWidth: number }; -type Stroke = Point[]; - -self.onmessage = (event) => { - const { width, height, strokes, maskStrokes } = event.data; - - if (event.data.type === 'init') { - offscreenCanvas = event.data.canvas; - ctx = offscreenCanvas!.getContext('2d')!; - return; - } - - if (event.data.type === 'draw') { - ctx.fillStyle = COLOR; - ctx.fillRect(0, 0, width, height); - - ctx.globalCompositeOperation = 'destination-out'; - - [...strokes].forEach((stroke: Stroke) => { - stroke.forEach((point: { x: number; y: number; lineWidth: number }) => { - const lineWidth = point.lineWidth; - ctx.fillStyle = 'rgba(0,0,0,1)'; - ctx.beginPath(); - ctx.arc(point.x, point.y, lineWidth / 2, 0, Math.PI * 2); - ctx.fill(); - }); - }); - - // points - maskStrokes?.forEach((stroke: Stroke) => { - stroke.forEach((point: { x: number; y: number; lineWidth: number }) => { - const lineWidth = 4; - ctx.fillStyle = 'rgba(0,0,0,1)'; - ctx.beginPath(); - ctx.arc(point.x, point.y, lineWidth / 2, 0, Math.PI * 2); - ctx.fill(); - }); - }); - - const newImageData = ctx.getImageData(0, 0, width, height); - self.postMessage({ type: 'done', imageData: newImageData }, [ - newImageData.data.buffer - ]); - } -}; - -export {}; diff --git a/src/components/image-editor/offscreen-worker.ts b/src/components/image-editor/offscreen-worker.ts deleted file mode 100644 index ee093035..00000000 --- a/src/components/image-editor/offscreen-worker.ts +++ /dev/null @@ -1,111 +0,0 @@ -let offscreenCanvas: OffscreenCanvas; -let ctx: OffscreenCanvasRenderingContext2D; - -const COLOR = 'rgba(0, 0, 255, 0.3)'; - -type Point = { x: number; y: number; lineWidth: number }; -type Stroke = Point[]; - -const postDone = () => { - const imageData = ctx.getImageData( - 0, - 0, - offscreenCanvas.width, - offscreenCanvas.height - ); - self.postMessage({ type: 'done', imageData }); -}; - -const drawFillRect = ( - ctx: OffscreenCanvasRenderingContext2D, - stroke: Stroke, - options: any -) => { - const { color } = options; - - stroke?.forEach(({ x, y }) => { - const width = options.lineWidth || 10; - - ctx.save(); - ctx.fillStyle = 'rgba(0,0,0,1)'; - ctx.globalCompositeOperation = 'destination-out'; - ctx.fillRect(x - width / 2, y - width / 2, width, width); - - ctx.globalCompositeOperation = 'source-over'; - ctx.fillStyle = color; - ctx.fillRect(x - width / 2, y - width / 2, width, width); - ctx.restore(); - }); -}; - -const drawStrokes = (strokes: Stroke[]) => { - strokes?.forEach((stroke) => { - drawFillRect(ctx, stroke, { - color: COLOR - }); - }); -}; - -const drawLine = ( - stroke: Stroke | Point[], - options: { - lineWidth?: number; - color: string; - compositeOperation: 'source-over' | 'destination-out'; - } -) => { - const { color, compositeOperation } = options; - ctx.lineCap = 'round'; - ctx.lineJoin = 'round'; - ctx.globalCompositeOperation = compositeOperation; - ctx.save(); - - ctx.beginPath(); - - stroke?.forEach((point, i) => { - const { x, y } = point; - ctx.lineWidth = point.lineWidth || 10; - if (i === 0) { - ctx.moveTo(x, y); - } else { - ctx.lineTo(x, y); - } - }); - if (compositeOperation === 'source-over') { - ctx.strokeStyle = color; - } - ctx.stroke(); - ctx.restore(); -}; - -const drawLines = (strokes: Stroke[]) => { - strokes?.forEach((stroke: Point[], index) => { - drawLine(stroke, { - color: COLOR, - compositeOperation: 'destination-out' - }); - - drawLine(stroke, { - color: COLOR, - compositeOperation: 'source-over' - }); - }); -}; - -self.onmessage = (event) => { - if (event.data.type === 'init') { - offscreenCanvas = event.data.canvas; - ctx = offscreenCanvas!.getContext('2d')!; - return; - } - - if (event.data.type === 'draw') { - ctx?.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height); - const { maskStrokes, strokes } = event.data; - drawStrokes(maskStrokes); - drawLines(strokes); - postDone(); - } -}; - -export {}; diff --git a/src/components/image-editor/tools-bar.tsx b/src/components/image-editor/tools-bar.tsx deleted file mode 100644 index d37ad677..00000000 --- a/src/components/image-editor/tools-bar.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import IconFont from '@/components/icon-font'; -import { KeyMap } from '@/config/hotkeys'; -import UploadImg from '@/pages/playground/components/upload-img'; -import { - ClearOutlined, - DownloadOutlined, - ExpandOutlined, - FormatPainterOutlined, - UndoOutlined -} from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Checkbox, Slider, Tooltip } from 'antd'; -import { CheckboxChangeEvent } from 'antd/es/checkbox'; -import React from 'react'; - -interface ToolsBarProps { - disabled: boolean; - loading: boolean; - lineWidth: number; - uploadButton?: React.ReactNode; - invertMask?: boolean; - accept?: string; - handleBrushSizeChange: (value: number) => void; - undo: () => void; - onClear: () => void; - handleFitView: () => void; - handleUpdateImageList: (fileList: any[]) => void; - handleUpdateMaskList: (fileList: any[]) => void; -} - -const ToolsBar: React.FC = (props) => { - const { - disabled, - loading, - lineWidth, - invertMask, - accept, - handleBrushSizeChange, - undo, - onClear, - handleFitView, - handleUpdateImageList, - handleUpdateMaskList - } = props; - const intl = useIntl(); - return ( -
- - - {intl.formatMessage({ id: 'playground.image.brushSize' })} - - -
- } - > - - - - [{KeyMap.UNDO.textKeybinding}] - - {intl.formatMessage({ id: 'common.button.undo' })} - - - } - > - - - - - - - } - disabled={loading || invertMask} - handleUpdateImgList={handleUpdateMaskList} - size="middle" - accept={accept} - > - - - -
- ); -}; - -interface ImageActionsBarProps { - disabled: boolean; - maskUpload?: any[]; - isOriginal: boolean; - invertMask: boolean; - handleOnChangeMask: (e: CheckboxChangeEvent) => void; - downloadMask: () => void; - download: () => void; -} - -const ImageActionsBar: React.FC = (props) => { - const intl = useIntl(); - const { - disabled, - isOriginal, - invertMask, - handleOnChangeMask, - downloadMask, - download - } = props; - return ( -
- {isOriginal && ( - <> - - {intl.formatMessage({ - id: 'playground.image.negativeMask.tips' - })} - - } - > - - - {intl.formatMessage({ - id: 'playground.image.negativeMask' - })} - - - - - - - - )} - {!isOriginal && ( - - - - )} -
- ); -}; - -export { ImageActionsBar, ToolsBar }; diff --git a/src/components/label-cell/index.tsx b/src/components/label-cell/index.tsx deleted file mode 100644 index bf0ff7cb..00000000 --- a/src/components/label-cell/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import _ from 'lodash'; -import React from 'react'; -import styled from 'styled-components'; - -const LabelsWrapper = styled.div` - display: flex; - flex-wrap: wrap; - gap: 6px; -`; - -interface LabelCellProps { - labels: Record; -} - -const LabelsCell: React.FC = ({ labels }) => ( - - {_.map(labels, (value: string, key: string) => ( - - {key} - :{value} - - ))} - -); - -export default LabelsCell; diff --git a/src/components/label-selector/autocomplete-item.tsx b/src/components/label-selector/autocomplete-item.tsx deleted file mode 100644 index bce8bf7b..00000000 --- a/src/components/label-selector/autocomplete-item.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import AutoComplete from '@/components/seal-form/auto-complete'; -import { MinusOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Tooltip } from 'antd'; -import _ from 'lodash'; -import React, { useMemo, useState } from 'react'; -import { useLabelSelectorContext } from './context'; -import './styles/label-item.less'; -interface LabelItemProps { - label: { - key: string; - value: string; - }; - labels?: Record; - labelKey?: string; - labelValue?: string; - keyAddon?: React.ReactNode; - valueAddon?: React.ReactNode; - seperator?: string; - labelList: { key: string; value: string }[]; - disabled?: boolean; - onDelete?: () => void; - onChange?: (params: { key: string; value: string }) => void; - onPaste?: (e: any) => void; - onBlur?: (e: any, type: string) => void; -} -const LabelItem: React.FC = ({ - labels, - label, - labelList, - seperator, - keyAddon, - valueAddon, - disabled, - onChange, - onDelete, - onBlur -}) => { - const intl = useIntl(); - const [open, setOpen] = useState(false); - const { options, placeholder = [] } = useLabelSelectorContext(); - - const keyOptions = useMemo(() => { - return options?.filter( - (item) => !_.has(labels, item.value) || item.value === label.key - ); - }, [labels, options]); - - const valueOptions = useMemo(() => { - return options?.find((item) => item.value === label.key)?.children || []; - }, [label.key, options]); - - const handleOnValueChange = (value: string) => { - onChange?.({ - key: label.key, - value: value - }); - }; - - const handleOnKeyChange = (key: any) => { - onChange?.({ - key, - value: label.value - }); - }; - - const handleKeyOnBlur = (e: any, type: string) => { - const val = e.target.value; - // has duplicate key - const duplicates = _.filter( - labelList, - (item: Global.BaseListItem) => val && val === item.key - ); - if (duplicates.length > 1) { - setOpen(true); - onChange?.({ - key: '', - value: label.value - }); - setTimeout(() => { - setOpen(false); - }, 1000); - } else { - setOpen(false); - } - onBlur?.(e, type); - }; - - return ( -
-
- {keyAddon ?? ( - - handleKeyOnBlur(e, 'key')} - > - - )} -
- {seperator && {seperator}} -
- {valueAddon ?? ( - onBlur?.(e, 'value')} - > - )} -
- {!disabled && ( - - )} -
- ); -}; - -export default LabelItem; diff --git a/src/components/label-selector/context.ts b/src/components/label-selector/context.ts deleted file mode 100644 index d13a49d1..00000000 --- a/src/components/label-selector/context.ts +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; - -interface LabelSelectorContextProps { - options?: Array<{ - label: string; - value: string | number; - children?: { label: string; value: string | number }[]; - }>; - placeholder?: string[]; - currentData?: Record; -} - -export const LabelSelectorContext = - React.createContext( - {} as LabelSelectorContextProps - ); - -export const useLabelSelectorContext = () => { - const context = React.useContext(LabelSelectorContext); - if (!context) { - throw new Error( - 'useLabelSelectorContext must be used within a LabelSelectorProvider' - ); - } - return context; -}; diff --git a/src/components/label-selector/index.tsx b/src/components/label-selector/index.tsx deleted file mode 100644 index b02180dc..00000000 --- a/src/components/label-selector/index.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useIntl } from '@umijs/max'; -import _ from 'lodash'; -import React, { useEffect, useState } from 'react'; -import Inner from './inner'; - -interface LabelSelectorProps { - labels: Record; - label?: string; - btnText?: string; - description?: React.ReactNode; - disabled?: boolean; - isAutoComplete?: boolean; - enablePaste?: boolean; - onChange?: (labels: Record) => void; - onBlur?: (e: any, type: string, index: number) => void; - onDelete?: (index: number) => void; -} - -const LabelSelector: React.FC = ({ - labels, - onChange, - onBlur, - onDelete, - disabled, - label, - btnText, - description, - isAutoComplete, - enablePaste = true -}) => { - const intl = useIntl(); - const [labelsData, setLabelsData] = useState({}); - const [labelList, setLabelList] = useState<{ key: string; value: string }[]>( - [] - ); - - useEffect(() => { - if (!_.isEqual(labels, labelsData)) { - setLabelsData(labels || {}); - const list = _.map(_.keys(labels), (key: string) => { - return { - key, - value: labels[key] - }; - }); - setLabelList(list); - } - }, [labels]); - - const handleLabelListChange = (list: { key: string; value: string }[]) => { - setLabelList(list); - }; - - const handleLabelsChange = (data: Record) => { - console.log('handleLabelsChange', data); - setLabelsData(data); - onChange?.(data); - }; - - const updateLabels = (list: { key: string; value: string }[]) => { - const newLabels = _.reduce( - list, - (result: any, item: any) => { - if (item.key) { - result[item.key] = item.value; - } - return result; - }, - {} - ); - onChange?.(newLabels); - }; - - const handleOnPaste = ( - e: React.ClipboardEvent, - index: number - ) => { - if (!enablePaste) return; - const clipboardText = e.clipboardData.getData('text'); - if (!clipboardText || clipboardText.indexOf('=') === -1) return; - e.preventDefault(); - - const lines = _.split(clipboardText, /\r?\n/) - .map((line: string) => line.trim()) - .filter((line: string) => line && line.includes('=')); - - const parsedData = lines.map((line: string) => { - const [key, value] = line.split(/=(.+)/).map((s) => s.trim()); - return { key, value }; - }); - - const newPairs = [...labelList]; - newPairs.splice(index, 1, ...parsedData); - - updateLabels(newPairs); - setLabelList(newPairs); - }; - - return ( - - ); -}; - -export default LabelSelector; diff --git a/src/components/label-selector/inner.tsx b/src/components/label-selector/inner.tsx deleted file mode 100644 index 3ea172e9..00000000 --- a/src/components/label-selector/inner.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import _ from 'lodash'; -import React from 'react'; -import AutoCompleteItem from './autocomplete-item'; -import LabelItem from './label-item'; -import Wrapper from './wrapper'; -interface LabelSelectorProps { - labels: Record; - label?: string; - btnText?: string; - isAutoComplete?: boolean; - labelList: Array<{ key: string; value: string }>; - onLabelListChange: (list: { key: string; value: string }[]) => void; - onChange?: (labels: Record) => void; - onPaste?: (e: any, index: number) => void; - onBlur?: (e: any, type: string, index: number) => void; - onDelete?: (index: number) => void; - description?: React.ReactNode; - disabled?: boolean; -} - -const Inner: React.FC = ({ - labels, - labelList, - onChange, - onLabelListChange, - onPaste, - onBlur, - onDelete, - disabled, - label, - btnText, - description, - isAutoComplete -}) => { - const updateLabels = (list: { key: string; value: string }[]) => { - const newLabels = _.reduce( - list, - (result: any, item: any) => { - if (item.key) { - result[item.key] = item.value; - } - return result; - }, - {} - ); - onChange?.(newLabels); - }; - const handleOnChange = (index: number, label: any) => { - const list = _.cloneDeep(labelList); - list[index] = label; - onLabelListChange(list); - updateLabels(list); - }; - - const handleAddLabel = () => { - const newLabelList = [ - ...labelList, - { - key: '', - value: '' - } - ]; - onLabelListChange(newLabelList); - updateLabels(newLabelList); - }; - - const handleOnDelete = (index: number) => { - const list = _.cloneDeep(labelList); - list.splice(index, 1); - onLabelListChange(list); - updateLabels(list); - onDelete?.(index); - }; - - return ( - - <> - {isAutoComplete - ? labelList?.map((item: any, index: number) => { - return ( - handleOnDelete(index)} - onChange={(obj) => handleOnChange(index, obj)} - onPaste={(e) => onPaste?.(e, index)} - onBlur={(e: any, type: string) => onBlur?.(e, type, index)} - /> - ); - }) - : labelList?.map((item: any, index: number) => { - return ( - handleOnDelete(index)} - onChange={(obj) => handleOnChange(index, obj)} - onPaste={(e) => onPaste?.(e, index)} - onBlur={(e: any, type: string) => onBlur?.(e, type, index)} - /> - ); - })} - - - ); -}; - -export default Inner; diff --git a/src/components/label-selector/label-item.tsx b/src/components/label-selector/label-item.tsx deleted file mode 100644 index f8425178..00000000 --- a/src/components/label-selector/label-item.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import SealInput from '@/components/seal-form/seal-input'; -import { MinusOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Tooltip } from 'antd'; -import _ from 'lodash'; -import React, { useState } from 'react'; -import './styles/label-item.less'; -interface LabelItemProps { - label: { - key: string; - value: string; - }; - labelKey?: string; - labelValue?: string; - keyAddon?: React.ReactNode; - valueAddon?: React.ReactNode; - seperator?: string; - labelList: { key: string; value: string }[]; - disabled?: boolean; - onDelete?: () => void; - onChange?: (params: { key: string; value: string }) => void; - onPaste?: (e: any) => void; - onBlur?: (e: any, type: string) => void; -} -const LabelItem: React.FC = ({ - label, - labelList, - seperator, - keyAddon, - valueAddon, - disabled, - onChange, - onDelete, - onPaste, - onBlur -}) => { - const intl = useIntl(); - const [open, setOpen] = useState(false); - - const handleOnValueChange = (e: any) => { - const value = e.target.value; - onChange?.({ - key: label.key, - value: value - }); - }; - - const handleOnKeyChange = (e: any) => { - const key = e.target.value; - onChange?.({ - key, - value: label.value - }); - }; - - const handleKeyOnBlur = (e: any, type: string) => { - const val = e.target.value; - // has duplicate key - const duplicates = _.filter( - labelList, - (item: Global.BaseListItem) => val && val === item.key - ); - if (duplicates.length > 1) { - setOpen(true); - onChange?.({ - key: '', - value: label.value - }); - setTimeout(() => { - setOpen(false); - }, 1000); - } else { - setOpen(false); - } - onBlur?.(e, type); - }; - - return ( -
-
- {keyAddon ?? ( - - - handleKeyOnBlur(e, 'key')} - onPaste={onPaste} - > - - - )} -
- {seperator && {seperator}} -
- {valueAddon ?? ( - onBlur?.(e, 'value')} - > - )} -
- {!disabled && ( - - )} -
- ); -}; - -export default LabelItem; diff --git a/src/components/label-selector/styles/label-item.less b/src/components/label-selector/styles/label-item.less deleted file mode 100644 index fab81bfe..00000000 --- a/src/components/label-selector/styles/label-item.less +++ /dev/null @@ -1,29 +0,0 @@ -.label-item { - display: flex; - margin-bottom: 12px; - align-items: center; - justify-content: flex-start; - - .seprator { - display: flex; - flex: none; - width: 12px; - align-items: center; - justify-content: center; - color: var(--ant-color-text-tertiary); - } - - .btn { - width: 24px; - margin-left: 10px; - flex: none; - } - - .label-key { - flex: 1; - } - - .label-value { - flex: 1; - } -} diff --git a/src/components/label-selector/wrapper.tsx b/src/components/label-selector/wrapper.tsx deleted file mode 100644 index 7c1c4ec4..00000000 --- a/src/components/label-selector/wrapper.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import LabelInfo from '@/components/seal-form/components/label-info'; -import { PlusOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -interface WrapperProps { - required?: boolean; - label?: React.ReactNode; - description?: React.ReactNode; - labelExtra?: React.ReactNode; - children: React.ReactNode; - btnText?: string; - disabled?: boolean; - onAdd?: () => void; - styles?: { - wrapper?: React.CSSProperties; - }; - button?: React.ReactNode; -} - -const Container = styled.div` - position: relative; - padding: 14px; - padding-top: 34px; - border: 1px solid var(--ant-color-border); - border-radius: var(--ant-border-radius-lg); - display: flex; - width: 100%; - flex-direction: column; - .label { - position: absolute; - left: 16px; - line-height: 1; - top: 12px; - color: var(--ant-color-text-tertiary); - } -`; - -const ButtonWrapper = styled.div` - margin-top: 8px; -`; - -const Wrapper: React.FC = ({ - required, - children, - label, - description, - labelExtra, - onAdd, - btnText, - disabled, - button, - styles -}) => { - const intl = useIntl(); - return ( - - {label && ( - - - - )} - {children} - {!disabled && ( - - {button || ( - - )} - - )} - - ); -}; - -export default Wrapper; diff --git a/src/components/list-input/hint-input.tsx b/src/components/list-input/hint-input.tsx deleted file mode 100644 index 43995f6f..00000000 --- a/src/components/list-input/hint-input.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import AutoComplete from '@/components/seal-form/auto-complete'; -import _ from 'lodash'; -import React from 'react'; - -interface HintInputProps { - value: string; - label?: string; - onChange: (value: string) => void; - onBlur?: (e: any) => void; - onPaste?: (e: any) => void; - placeholder?: string; - trim?: boolean; - sourceOptions?: Global.HintOptions[]; -} - -const matchReg = /[^=]+=[^=]*$/; - -const HintInput: React.FC = (props) => { - const { - value, - label, - onChange, - onBlur, - onPaste, - sourceOptions, - trim = true - } = props; - const cursorPosRef = React.useRef(0); - const contextBeforeCursorRef = React.useRef(''); - const [options, setOptions] = React.useState< - Array> - >([]); - - const generateOptions = (context: string) => { - if (!context) { - setOptions(sourceOptions || []); - return; - } - const match = context.match(matchReg); - if (!match) { - const list = _.filter(sourceOptions, (item: Global.HintOptions) => - item.label.includes(context) - ); - setOptions(list); - return; - } - const [key, value] = _.split(match[0], '='); - const data = _.find( - sourceOptions, - (item: Global.HintOptions) => item.label === key - ); - if (!data) { - setOptions([]); - return; - } - const list = _.filter(data.opts, (item: Global.BaseOption) => - item.label.includes(value) - ); - setOptions(list); - }; - - const replaceLastEqual = (value: string) => { - const matchStr = contextBeforeCursorRef.current.match(matchReg); - if (matchStr) { - const arr = _.split(matchStr[0], '='); - onChange(`${arr[0]}=${value}`); - } else { - onChange(value?.trim()); - } - }; - - const getContextBeforeCursor = _.debounce((e: any) => { - cursorPosRef.current = e.target.selectionStart; - contextBeforeCursorRef.current = e.target.value.slice( - 0, - cursorPosRef.current - ); - generateOptions(contextBeforeCursorRef.current); - }, 100); - - const handleInput = (e: any) => { - getContextBeforeCursor(e); - onChange(e.target.value); - }; - - const handleOnSelect = (value: string) => { - replaceLastEqual(value); - setOptions([]); - }; - - return ( - - ); -}; - -export default HintInput; diff --git a/src/components/list-input/index.tsx b/src/components/list-input/index.tsx deleted file mode 100644 index 677121c7..00000000 --- a/src/components/list-input/index.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { parseParamsString } from '@/utils'; -import _ from 'lodash'; -import React, { useEffect } from 'react'; -import Wrapper from '../label-selector/wrapper'; -import ListItem from './list-item'; - -interface ListInputProps { - required?: boolean; - dataList: string[]; - label?: React.ReactNode; - description?: React.ReactNode; - btnText?: string; - options?: Global.HintOptions[]; - placeholder?: string; - labelExtra?: React.ReactNode; - trim?: boolean; - styles?: { - wrapper?: React.CSSProperties; - item?: React.CSSProperties; - }; - onChange: (data: string[]) => void; - onBlur?: (e: any, index: number) => void; - onDelete?: (index: number) => void; - renderItem?: ( - data: any, - props: { - onChange: (value: string) => void; - onBlur?: (e: any) => void; - } - ) => React.ReactNode; -} - -const ListInput: React.FC = (props) => { - const { - dataList, - label, - description, - onChange, - onBlur, - onDelete, - btnText, - options, - labelExtra, - trim = true, - styles, - required, - renderItem - } = props; - const [list, setList] = React.useState<{ value: string; uid: number }[]>([]); - const countRef = React.useRef(0); - - const updateCountRef = () => { - countRef.current = countRef.current + 1; - }; - - const handleOnRemove = (index: number) => { - const values = _.cloneDeep(list); - values.splice(index, 1); - const valueList = _.map(values, 'value').filter((val: string) => !!val); - setList(values); - onChange(valueList); - onDelete?.(index); - }; - - const handleOnChange = (value: string, index: number) => { - const values = _.cloneDeep(list); - values[index].value = value; - const valueList = _.map(values, 'value').filter((val: string) => !!val); - setList(values); - onChange(valueList); - }; - - const handleOnAdd = () => { - updateCountRef(); - const values = _.cloneDeep(list); - values.push({ - value: '', - uid: countRef.current - }); - setList(values); - }; - - const handleOnPaste = (e: any, index: number) => { - const pastedText = e.clipboardData?.getData('text'); - if (!pastedText) return; - - const lines = parseParamsString(pastedText); - - if (lines.length <= 1) { - // if there's only one line, let the default paste behavior handle it - return; - } - - e.preventDefault(); - - const values = _.cloneDeep(list); - - // replace the current item with the first line of the pasted text - values[index].value = trim ? lines[0].trim() : lines[0]; - - // create new list items for the remaining lines - for (let i = 1; i < lines.length; i++) { - updateCountRef(); - values.splice(index + i, 0, { - value: trim ? lines[i].trim() : lines[i], - uid: countRef.current - }); - } - - const valueList = _.map(values, 'value').filter((val: string) => !!val); - setList(values); - onChange(valueList); - }; - - React.useEffect(() => { - const valueList = _.map(list, 'value').filter((val: string) => !!val); - if (!_.isEqual(valueList, dataList)) { - const values = _.map(dataList, (value: string) => { - updateCountRef(); - return { - value, - uid: countRef.current - }; - }); - setList(values); - } - }, [dataList]); - - useEffect(() => { - if (required && list.length === 0) { - handleOnAdd(); - } - }, [required]); - - return ( - - <> - {_.map(list, (item: any, index: number) => { - return ( - onBlur?.(e, index)} - onRemove={() => handleOnRemove(index)} - onChange={(val) => handleOnChange(val, index)} - onPaste={(e) => handleOnPaste(e, index)} - trim={trim} - renderItem={renderItem} - /> - ); - })} - - - ); -}; - -export default ListInput; diff --git a/src/components/list-input/list-item.tsx b/src/components/list-input/list-item.tsx deleted file mode 100644 index 8e768347..00000000 --- a/src/components/list-input/list-item.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { MinusOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React from 'react'; -import HintInput from './hint-input'; -import './styles/list-item.less'; - -interface LabelItemProps { - onRemove: () => void; - onChange: (value: string) => void; - onBlur?: (e: any) => void; - onPaste?: (e: any) => void; - renderItem?: ( - data: any, - props: { - onChange: (value: string) => void; - onBlur?: (e: any) => void; - onPaste?: (e: any) => void; - } - ) => React.ReactNode; - value: string; - label?: string; - placeholder?: string; - options?: Global.HintOptions[]; - trim?: boolean; - data?: any; - required?: boolean; -} - -const ListItem: React.FC = (props) => { - const { - onRemove, - onChange, - onBlur, - onPaste, - label, - value, - options, - trim = true, - data, - required, - renderItem - } = props; - - const handleOnChange = (value: any) => { - onChange(value); - }; - - return ( -
- {renderItem ? ( - renderItem(data, { - onChange: handleOnChange, - onBlur, - onPaste - }) - ) : ( - - )} - {!required && ( -
- ); -}; - -export default ListItem; diff --git a/src/components/list-input/style/list-item.less b/src/components/list-input/style/list-item.less deleted file mode 100644 index 3eb71d85..00000000 --- a/src/components/list-input/style/list-item.less +++ /dev/null @@ -1,15 +0,0 @@ -.list-item { - display: flex; - align-items: center; - justify-content: flex-start; - width: 100%; - margin-bottom: 12px; - - .field-wrapper { - flex: 1; - } - - .btn { - margin-left: 10px; - } -} diff --git a/src/components/list-input/styles/list-item.less b/src/components/list-input/styles/list-item.less deleted file mode 100644 index 3eb71d85..00000000 --- a/src/components/list-input/styles/list-item.less +++ /dev/null @@ -1,15 +0,0 @@ -.list-item { - display: flex; - align-items: center; - justify-content: flex-start; - width: 100%; - margin-bottom: 12px; - - .field-wrapper { - flex: 1; - } - - .btn { - margin-left: 10px; - } -} diff --git a/src/components/logs-viewer/config.ts b/src/components/logs-viewer/config.ts deleted file mode 100644 index f7f52ff2..00000000 --- a/src/components/logs-viewer/config.ts +++ /dev/null @@ -1,33 +0,0 @@ -export const controlSeqRegex = /\x1b\[(\d*);?(\d*)?([A-DJKHfm])/g; -export const replaceLineRegex = /\r\n/g; - -export const PageSize = 1000; - -export const throttle = void>( - func: T, - wait: number -): ((this: ThisParameterType, ...args: Parameters) => void) => { - let timeout: ReturnType | null = null; - let previous = Date.now(); - - return function (this: ThisParameterType, ...args: Parameters): void { - const now = Date.now(); - const remaining = wait - (now - previous); - const context = this as ThisParameterType; - - if (remaining <= 0 || remaining > wait) { - if (timeout) { - clearTimeout(timeout); - timeout = null; - } - previous = now; - func.apply(context, args); - } else if (!timeout) { - timeout = setTimeout(() => { - previous = Date.now(); - timeout = null; - func.apply(context, args); - }, remaining); - } - }; -}; diff --git a/src/components/logs-viewer/logs-list.tsx b/src/components/logs-viewer/logs-list.tsx deleted file mode 100644 index 95fe2515..00000000 --- a/src/components/logs-viewer/logs-list.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import useOverlayScroller from '@/hooks/use-overlay-scroller'; -import classNames from 'classnames'; -import _, { throttle } from 'lodash'; -import React, { - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useRef, - useState -} from 'react'; -import './styles/logs-list.less'; - -interface LogsListProps { - dataList: any[]; - height?: number; - onScroll?: (data: { isTop: boolean; isBottom: boolean }) => void; - diffHeight?: number; - showNum?: boolean; - ref?: any; -} -const LogsList: React.FC = forwardRef((props, ref) => { - const { dataList, height, showNum, onScroll, diffHeight = 96 } = props; - const { - initialize, - updateScrollerPosition, - updateScrollerPositionToTop, - generateInstance, - scrollEventElement, - instance, - initialized - } = useOverlayScroller({ - options: { - scrollbars: { - theme: 'os-theme-light' - } - } - }); - const [innerHieght, setInnerHeight] = useState( - window.innerHeight - diffHeight - ); - const scroller = useRef({}); - const stopScroll = useRef(false); - - const scrollToBottom = useCallback(() => { - updateScrollerPosition(0); - }, [updateScrollerPosition]); - - const debounceResetStopScroll = _.debounce(() => { - stopScroll.current = false; - }, 30000); - - const scrollToTop = useCallback(() => { - stopScroll.current = true; - updateScrollerPositionToTop(); - debounceResetStopScroll(); - }, [updateScrollerPositionToTop]); - - useImperativeHandle(ref, () => ({ - scrollToBottom, - scrollToTop, - scroller: scroller.current - })); - - const handleOnWheel = (e: any) => { - const scrollTop = scrollEventElement?.current?.scrollTop; - const scrollHeight = scrollEventElement?.current?.scrollHeight; - const clientHeight = scrollEventElement?.current?.clientHeight; - - stopScroll.current = scrollTop + clientHeight <= scrollHeight; - - const isBottom = scrollTop + clientHeight + 150 >= scrollHeight; - // is scroll to top - if (scrollTop <= 10) { - onScroll?.({ - isTop: true, - isBottom: false - }); - } else if (isBottom) { - onScroll?.({ - isTop: false, - isBottom: true - }); - stopScroll.current = false; - } else { - onScroll?.({ - isTop: false, - isBottom: false - }); - } - }; - - const debounceUpdateScrollerPosition = _.debounce(() => { - generateInstance(); - updateScrollerPosition(0); - }, 200); - - useEffect(() => { - const handleResize = throttle(() => { - const viewportHeight = window.innerHeight; - const viewHeight = viewportHeight - diffHeight; - setInnerHeight(viewHeight); - }, 100); - window.addEventListener('resize', handleResize); - return () => { - window.removeEventListener('resize', handleResize); - }; - }, [diffHeight]); - - useEffect(() => { - if (scroller.current) { - initialize(scroller.current); - } - }, [initialize]); - - useEffect(() => { - if (dataList.length && !stopScroll.current && instance) { - updateScrollerPosition(0); - } else if (dataList.length && !stopScroll.current && scroller.current) { - if (!initialized) { - initialize(scroller.current); - } - if (!instance) { - debounceUpdateScrollerPosition(); - } else { - updateScrollerPosition(0); - } - } - }, [dataList, stopScroll.current, instance, scroller.current]); - - return ( -
-
- {_.map(dataList, (item: any, index: number) => { - return ( -
- {item.content} -
- ); - })} -
-
- ); -}); - -export default React.memo(LogsList); diff --git a/src/components/logs-viewer/logs-pagination.tsx b/src/components/logs-viewer/logs-pagination.tsx deleted file mode 100644 index 868ee8dc..00000000 --- a/src/components/logs-viewer/logs-pagination.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { - DownOutlined, - UpOutlined, - VerticalLeftOutlined -} from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Tooltip } from 'antd'; -import React from 'react'; -import './styles/pagination.less'; - -interface LogsPaginationProps { - page: number; - total: number; - pageSize?: number; - onPrev?: () => void; - onNext?: () => void; - onBackend?: () => void; - onToFirst?: () => void; -} - -const LogsPagination: React.FC = (props) => { - const { page, total, pageSize, onNext, onPrev, onBackend, onToFirst } = props; - const intl = useIntl(); - - const handleOnPrev = () => { - onPrev?.(); - }; - - const handleOnNext = () => { - onNext?.(); - }; - - return ( -
- { - <> - - - - - - - - } - - {page} /{' '} - {total} - - {page < total && ( - <> - - - - - - - - )} -
- ); -}; - -export default LogsPagination; diff --git a/src/components/logs-viewer/parse-worker.ts b/src/components/logs-viewer/parse-worker.ts deleted file mode 100644 index 8ed82206..00000000 --- a/src/components/logs-viewer/parse-worker.ts +++ /dev/null @@ -1,315 +0,0 @@ -import { controlSeqRegex } from './config'; - -const removeBrackets = (str: string) => { - return str?.replace?.(/^\(…\)/, ''); -}; - -const removeBracketsFromLine = (row: string) => { - return row.startsWith('(…)') ? row.slice(3) : row; -}; - -interface MessageProps { - inputStr: string; - reset?: boolean; - page?: number; - isComplete?: boolean; - chunked?: boolean; - progress?: number; - percent?: number; - isDownloading?: boolean; -} -class AnsiParser { - private cursorRow: number = 0; - private cursorCol: number = 0; - private screen: string[][] = [['']]; - private rawDataRows: number = 0; - private uid: number = 0; - private isProcessing: boolean = false; - private taskQueue: string[] = []; - private page: number = 1; - private progress: number = 0; - private percent: number = 0; - private isComplete: boolean = false; - private chunked: boolean = true; // true: send data in chunks, false: send all data at once - private reminder: string = ''; - private lines: string[] = []; - isDownloading: boolean = false; - private pageSize: number = 500; - private colorMap = { - '30': 'black', - '31': 'red', - '32': 'green', - '33': 'yellow', - '34': 'blue', - '35': 'magenta', - '36': 'cyan', - '37': 'white' - }; - - constructor() { - this.reset(); - } - - public reset() { - this.cursorRow = 0; - this.cursorCol = 0; - this.screen = [['']]; - this.rawDataRows = 0; - this.uid = this.uid + 1; - this.lines = []; - this.reminder = ''; - this.page = 1; - } - - public setPage(page: number | undefined) { - this.page = page ?? 1; - } - - public setPercent(percent: number | undefined) { - this.percent = percent ?? 0; - } - - public setProgress(progress: number | undefined) { - this.progress = progress ?? 0; - } - - public setIsCompelete(isComplete: boolean) { - this.isComplete = isComplete; - } - - public setChunked(chunked: boolean) { - this.chunked = chunked ?? true; - } - - public setIsDownloading(isDownloading: boolean) { - this.isDownloading = isDownloading; - } - - private setId() { - this.uid += 1; - return this.uid; - } - - private handleText(text: string) { - for (let i = 0; i < text.length; i++) { - let char = text[i]; - if (char === '\r') { - let nextChar = text[i + 1]; - if (nextChar === '\n') { - continue; // windows new line: \r\n - } else { - this.cursorCol = 0; // move to the beginning of the line - } - } else if (char === '\n') { - this.rawDataRows++; - this.cursorRow++; - this.cursorCol = 0; // back to the beginning of the line - if (!this.screen[this.cursorRow]) { - this.screen[this.cursorRow] = ['']; - } - } else { - const currentLine = this.screen[this.cursorRow]; - currentLine[this.cursorCol] = char; - this.cursorCol++; - } - } - } - - private handleAnsiSequence(match: RegExpExecArray, isEnd: boolean) { - const n = parseInt(match[1] || '1', 10); - const m = parseInt(match[2] || '1', 10); - const command = match[3]; - switch (command) { - case 'A': - this.cursorRow = Math.max(0, this.cursorRow - n); - break; - case 'B': - this.cursorRow += n; - break; - case 'C': // move the cursor to the right - this.cursorCol += n; - break; - case 'D': // move the cursor to the left - this.cursorCol = Math.max(0, this.cursorCol - n); - break; - case 'H': // move the cursor to the specified position (n, m) - this.cursorRow = Math.max(0, n - 1); - this.cursorCol = Math.max(0, m - 1); - break; - case 'J': // clear the screen - if (n === 2) { - this.reset(); - } - break; - case 'm': - // if (match[1] === '0') { - // currentStyle = ''; - // } else if (colorMap[match[1]]) { - // currentStyle = `color: ${colorMap[match[1]]};`; - // } - break; - } - - while (this.screen.length <= this.cursorRow && !isEnd) { - this.screen.push(['']); - } - while (this.screen[this.cursorRow].length <= this.cursorCol && !isEnd) { - this.screen[this.cursorRow].push(''); - } - } - - private processInput(input: string) { - let match: RegExpExecArray | null; - let lastIndex = 0; - - while ((match = controlSeqRegex.exec(input)) !== null) { - const textBeforeControl = input.slice(lastIndex, match.index); - this.handleText(textBeforeControl); - - lastIndex = controlSeqRegex.lastIndex; - - this.handleAnsiSequence(match, lastIndex === input.length - 1); - } - - const remainingText = input.slice(lastIndex); - this.handleText(remainingText); - - // const result = this.screen.map((row, index) => ({ - // content: removeBracketsFromLine(row.join('')), - // uid: `${this.page}-${index}` - // })); - const result = this.screen.map((row, index) => - removeBracketsFromLine(row.join('')) - ); - - return { - data: result, - lines: this.rawDataRows, - remainder: '' - }; - } - - private getScreenText() { - const result = this.screen - .map((row) => removeBracketsFromLine(row.join(''))) - .join('\n'); - return result; - } - - private processInputByLine(input: string): { - data: string[]; - lines: number; - remainder: string; - } { - const lines = input?.split(/\r?\n/) || []; - const remainder = lines.pop() || ''; - - // const data = lines.join('\n'); - this.rawDataRows += lines.length; - lines.forEach((line) => { - this.lines.push(line); - }); - - return { - data: this.lines, - lines: this.rawDataRows, - remainder - }; - } - - private getAllLines() { - return this.lines.join('\n'); - } - - private async processQueue(): Promise { - if (this.isProcessing) { - return; - } - - this.isProcessing = true; - - while (this.taskQueue.length > 0) { - let input = ''; - - if (this.isDownloading) { - input = this.taskQueue.shift() || ''; - } else { - input = this.reminder + this.taskQueue.shift(); - } - - if (input) { - try { - const result = this.isDownloading - ? this.processInput(input) - : this.processInputByLine(input); - if (!this.isDownloading) { - this.reminder = result.remainder; - } - - if (this.chunked) { - self.postMessage({ result: result.data, lines: result.lines }); - } else if (!this.isComplete) { - self.postMessage({ - result: '', - percent: this.percent, - isComplete: false - }); - } - } catch (error) { - console.error('Error processing input:', error); - } - } - - await new Promise((resolve) => { - setTimeout(resolve, 0); - }); - } - - this.isProcessing = false; - if (this.taskQueue.length > 0) { - this.processQueue(); - } else if (this.isComplete && !this.chunked) { - self.postMessage({ - result: this.getAllLines(), - percent: this.percent, - isComplete: true - }); - this.reset(); - } - } - - public enqueueData(input: string): void { - this.taskQueue.push(input); - if (!this.isProcessing) { - this.processQueue(); - } - } -} -const parser = new AnsiParser(); - -self.onmessage = function (event: MessageEvent) { - const { - inputStr, - reset, - page, - isComplete = false, - chunked = true, - percent = 0, - isDownloading = false - } = event.data; - - parser.setIsDownloading(isDownloading); - parser.setPage(page); - parser.setIsCompelete(isComplete); - parser.setChunked(chunked); - parser.setPercent(percent); - - if (reset) { - parser.reset(); - } - parser.enqueueData(inputStr); -}; - -self.onerror = function (event) { - console.error('parse logs error===', event); -}; diff --git a/src/components/logs-viewer/styles/index.less b/src/components/logs-viewer/styles/index.less deleted file mode 100644 index e5d33bcc..00000000 --- a/src/components/logs-viewer/styles/index.less +++ /dev/null @@ -1,126 +0,0 @@ -.logs-viewer-wrap-w2 { - position: relative; - - .pg { - position: absolute; - top: 16px; - right: 20px; - width: 40px; - height: 130px; - - .pg-inner { - position: relative; - - &::before { - content: ''; - position: absolute; - top: 0; - bottom: 0; - right: -18px; - // width: 80px; - height: 185px; - - &:hover { - .pagination { - display: flex; - } - } - } - - .pagination { - display: none; - } - - &:hover { - .pagination { - display: flex; - } - } - - &.at-top { - .pagination { - display: flex; - } - } - } - } - - .loading { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 100; - padding-top: 100px; - display: flex; - justify-content: center; - background-color: var(--color-fill-spin-bg); - } - - .copy { - position: absolute; - top: 10px; - right: 10px; - z-index: 100; - - button { - color: rgba(255, 255, 255, 70%); - background-color: rgba(71, 71, 71, 100%); - - &:hover { - color: rgba(255, 255, 255, 90%) !important; - background-color: rgba(71, 71, 71, 100%) !important; - } - } - } - - .wrap { - padding: 5px 0 2px 10px; - background-color: var(--color-logs-bg); - border-radius: var(--border-radius-mini); - font-family: monospace, Menlo, Courier, 'Courier New', Consolas, Monaco, - 'Liberation Mono' !important; - - .content { - word-wrap: break-word; - height: 100%; - padding-right: 2px; - - &.line-break { - word-wrap: break-word; - } - - .text { - min-height: 22px; - } - - color: var(--color-logs-text); - font-size: var(--font-size-small); - line-height: 22px; - white-space: pre-wrap; - background-color: var(--color-logs-bg); - } - } - - .xterm { - .xterm-viewport { - overflow-y: auto !important; - - &::-webkit-scrollbar { - width: var(--scrollbar-size); - height: var(--scrollbar-size); - } - - &::-webkit-scrollbar-thumb { - background-color: var(--color-scrollbar-thumb); - border-radius: 4px; - } - - &::-webkit-scrollbar-track { - background-color: var(--color-scrollbar-track); - border-radius: 4px; - } - } - } -} diff --git a/src/components/logs-viewer/styles/logs-list.less b/src/components/logs-viewer/styles/logs-list.less deleted file mode 100644 index 2c4eb669..00000000 --- a/src/components/logs-viewer/styles/logs-list.less +++ /dev/null @@ -1,44 +0,0 @@ -.logs-wrap { - background-color: var(--color-logs-bg); - border-radius: var(--border-radius-mini); - font-family: - monospace, Menlo, Courier, 'Courier New', Consolas, Monaco, - 'Liberation Mono' !important; - - .content { - word-wrap: break-word; - height: 100%; - padding-right: 2px; - - &.line-break { - word-wrap: break-word; - } - - .text { - min-height: 22px; - padding-inline-end: 80px; - - &.numable { - position: relative; - padding-left: 45px; - - .line-num { - display: flex; - align-items: center; - width: 40px; - justify-content: center; - position: absolute; - left: 0; - top: 0; - background-color: rgba(71, 71, 71, 50%); - } - } - } - - color: var(--color-logs-text); - font-size: 12px; - line-height: 22px; - white-space: pre-wrap; - background-color: var(--color-logs-bg); - } -} diff --git a/src/components/logs-viewer/styles/pagination.less b/src/components/logs-viewer/styles/pagination.less deleted file mode 100644 index db723688..00000000 --- a/src/components/logs-viewer/styles/pagination.less +++ /dev/null @@ -1,25 +0,0 @@ -.pagination { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - color: rgba(255, 255, 255, 100%); - gap: 5px; - - .ant-btn:hover { - color: rgba(255, 255, 255, 90%) !important; - background-color: rgba(71, 71, 71, 100%) !important; - } - - .ant-btn { - background-color: rgba(71, 71, 71, 70%) !important; - } - - .pages { - display: flex; - justify-content: center; - align-items: center; - height: 38px; - width: 38px; - } -} diff --git a/src/components/logs-viewer/styles/xterm-viewer.less b/src/components/logs-viewer/styles/xterm-viewer.less deleted file mode 100644 index 058e2b9d..00000000 --- a/src/components/logs-viewer/styles/xterm-viewer.less +++ /dev/null @@ -1,50 +0,0 @@ -.logs-viewer-wrap-w2 { - .wrap { - padding: 5px 0 5px 10px; - background-color: var(--color-logs-bg); - border-radius: var(--border-radius-mini); - overflow: hidden; - - .content { - word-wrap: break-word; - height: 100%; - - &.line-break { - word-wrap: break-word; - } - - .text { - height: 100%; - } - - color: var(--color-logs-text); - font-size: var(--font-size-small); - line-height: 22px; - white-space: pre-wrap; - background-color: var(--color-logs-bg); - } - } - - .xterm { - // height: 100% !important; - - .xterm-viewport { - overflow-y: auto !important; - - &::-webkit-scrollbar { - width: var(--scrollbar-size); - height: var(--scrollbar-size); - } - - &::-webkit-scrollbar-thumb { - background-color: var(--color-scrollbar-thumb); - border-radius: 4px; - } - - &::-webkit-scrollbar-track { - background-color: var(--color-scrollbar-track); - border-radius: 4px; - } - } - } -} diff --git a/src/components/logs-viewer/use-logs-pagination.ts b/src/components/logs-viewer/use-logs-pagination.ts deleted file mode 100644 index 06bf7be0..00000000 --- a/src/components/logs-viewer/use-logs-pagination.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { useState } from 'react'; -import { PageSize } from './config'; - -const useLogsPagination = () => { - const [pageSize, setPageSize] = useState(PageSize); - const [page, setPage] = useState(1); - const [total, setTotal] = useState(1); - - const nextPage = () => { - setPage(page + 1); - }; - - const prePage = () => { - let newPage = page - 1; - if (newPage < 1) { - newPage = 1; - } - setPage(newPage); - }; - - const resetPage = () => { - setPage(1); - }; - - const setTotalPage = (total: number) => { - setTotal(total); - }; - - return { - nextPage, - resetPage, - prePage, - setPage, - pageSize, - setTotalPage, - page, - totalPage: total - }; -}; - -export default useLogsPagination; diff --git a/src/components/logs-viewer/use-size.ts b/src/components/logs-viewer/use-size.ts deleted file mode 100644 index f1fac2c0..00000000 --- a/src/components/logs-viewer/use-size.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect, useState } from 'react'; - -export const useResizeObserver = (ref: React.RefObject) => { - const [size, setSize] = useState({ width: 0, height: 0 }); - - useEffect(() => { - const element = ref.current; - if (!element) return; - - const updateSize = () => { - const rect = element.getBoundingClientRect(); - setSize((prev) => { - if (prev.width === rect.width && prev.height === rect.height) - return prev; - return { width: rect.width, height: rect.height }; - }); - }; - - const observer = new ResizeObserver(() => { - updateSize(); - }); - - observer.observe(element); - updateSize(); - - return () => { - observer.disconnect(); - }; - }, [ref.current]); - - return size; -}; - -export default useResizeObserver; diff --git a/src/components/logs-viewer/virtual-log-list.tsx b/src/components/logs-viewer/virtual-log-list.tsx deleted file mode 100644 index 9c65371a..00000000 --- a/src/components/logs-viewer/virtual-log-list.tsx +++ /dev/null @@ -1,345 +0,0 @@ -import useSetChunkFetch from '@/hooks/use-chunk-fetch'; -import { useMemoizedFn } from 'ahooks'; -import { Spin } from 'antd'; -import classNames from 'classnames'; -import _ from 'lodash'; -import React, { - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useRef, - useState -} from 'react'; -import LogsList from './logs-list'; -import LogsPagination from './logs-pagination'; -import './styles/index.less'; -import useLogsPagination from './use-logs-pagination'; - -interface LogsViewerProps { - height?: number; - content?: string; - url: string; - params?: object; - ref?: any; - tail?: number; - enableScorllLoad?: boolean; - diffHeight?: number; - isDownloading?: boolean; -} - -const LogsViewer: React.FC = forwardRef((props, ref) => { - const { - diffHeight, - url, - tail: defaultTail, - enableScorllLoad = true, - isDownloading - } = props; - const { pageSize, page, setPage, setTotalPage, totalPage } = - useLogsPagination(); - const { setChunkFetch } = useSetChunkFetch(); - const chunkRequedtRef = useRef(null); - const [logs, setLogs] = useState([]); - const logParseWorker = useRef(null); - const tail = useRef(defaultTail); - const [loading, setLoading] = useState(false); - const [isAtTop, setIsAtTop] = useState(false); - const [scrollPos, setScrollPos] = useState([]); - const logListRef = useRef(null); - const loadMoreDone = useRef(false); - const pageRef = useRef(page); - const totalPageRef = useRef(totalPage); - const isLoadingMoreRef = useRef(false); - const [currentData, setCurrentPageData] = useState([]); - const scrollPosRef = useRef({ - pos: 'bottom', - page: 1 - }); - const lineCountRef = useRef(0); - const clearScreen = useRef(false); - - useImperativeHandle(ref, () => ({ - abort() { - chunkRequedtRef.current?.current?.abort?.(); - logParseWorker.current?.terminate?.(); - } - })); - - const removeBracketsFromLine = (row: string) => { - return row.startsWith('(…)') ? row.slice(3) : row; - }; - - const setCurrentData = (lines: string[]) => { - const dataList = lines.map((line, index) => { - return { - content: line, - uid: `${pageRef.current}-${index}` - }; - }); - - setCurrentPageData(dataList); - }; - - const debounceLoading = _.debounce(() => { - setLoading(false); - isLoadingMoreRef.current = false; - if (logListRef.current?.scroller) { - logListRef.current.scroller.style['pointer-events'] = 'auto'; - } - }, 1000); - - const getCurrent = useCallback(() => { - if (pageRef.current < 1) { - pageRef.current = 1; - } - const start = (pageRef.current - 1) * pageSize; - const end = pageRef.current * pageSize; - const currentLogs = logs.slice(start, end); - setPage(pageRef.current); - setCurrentData(currentLogs); - }, [logs, pageSize]); - - const getPrePage = useCallback(() => { - pageRef.current = pageRef.current - 1; - - getCurrent(); - - setScrollPos(['bottom', pageRef.current]); - scrollPosRef.current = { - pos: 'bottom', - page: pageRef.current - }; - }, [getCurrent]); - - const getNextPage = useCallback(() => { - pageRef.current = pageRef.current + 1; - - getCurrent(); - - setScrollPos(['top', pageRef.current]); - scrollPosRef.current = { - pos: 'top', - page: pageRef.current - }; - }, [getCurrent]); - - const handleonBackend = useCallback(() => { - pageRef.current = totalPageRef.current; - getCurrent(); - - console.log('pageRef.current', pageRef.current); - setScrollPos(['bottom', pageRef.current]); - scrollPosRef.current = { - pos: 'bottom', - page: pageRef.current - }; - }, [getCurrent]); - - const handleonToFirst = useCallback(() => { - pageRef.current = 1; - getCurrent(); - setScrollPos(['top', pageRef.current]); - scrollPosRef.current = { - pos: 'top', - page: pageRef.current - }; - }, [getCurrent]); - - const updateContent = (data: string) => { - if (isLoadingMoreRef.current) { - setLoading(true); - if (logListRef.current?.scroller) { - logListRef.current.scroller.style['pointer-events'] = 'none'; - } - } - logParseWorker.current.postMessage({ - inputStr: data, - page: pageRef.current, - reset: clearScreen.current, - isDownloading: isDownloading - }); - clearScreen.current = false; - }; - - const createChunkConnection = async () => { - chunkRequedtRef.current?.current?.abort?.(); - chunkRequedtRef.current = setChunkFetch({ - url, - params: { - ...props.params, - tail: tail.current, - watch: true - }, - contentType: 'text', - handler: updateContent - }); - }; - - const handleOnScroll = useMemoizedFn( - async (data: { isTop: boolean; isBottom: boolean }) => { - const { isTop, isBottom } = data; - setIsAtTop(isTop); - if (isBottom) { - scrollPosRef.current = { - pos: 'bottom', - page: page - }; - } else if (isTop) { - scrollPosRef.current = { - pos: 'top', - page: page - }; - } else { - scrollPosRef.current = { - pos: 'middle', - page: page - }; - } - if ( - loading || - (logs.length > 0 && - lineCountRef.current < pageSize - 1 && - !loadMoreDone.current) || - !enableScorllLoad - ) { - return; - } - - if (isTop && !loadMoreDone.current) { - tail.current = undefined; - createChunkConnection(); - loadMoreDone.current = true; - isLoadingMoreRef.current = true; - clearScreen.current = true; - } else if (isTop && page <= totalPage && page > 1) { - // getPrePage(); - } else if (isBottom && page < totalPage) { - // getNextPage(); - } - } - ); - - const debouncedScroll = useCallback( - _.throttle(() => { - if (scrollPos[0] === 'top' && scrollPosRef.current.pos === 'top') { - logListRef.current?.scrollToTop(); - } - if (scrollPosRef.current.pos === 'bottom') { - logListRef.current?.scrollToBottom(); - } - }, 150), - [scrollPos] - ); - - useEffect(() => { - createChunkConnection(); - return () => { - chunkRequedtRef.current?.current?.abort?.(); - }; - }, [url, isDownloading]); - - useEffect(() => { - debouncedScroll(); - }, [scrollPos]); - - useEffect(() => { - logParseWorker.current?.terminate?.(); - - logParseWorker.current = new Worker( - // @ts-ignore - new URL('./parse-worker.ts', import.meta.url), - { - type: 'module' - } - ); - - logParseWorker.current.onmessage = (event: any) => { - const { result, lines } = event.data; - lineCountRef.current = lines; - - if (pageRef.current < 1) { - pageRef.current = 1; - } - - const oldTotalPage = totalPageRef.current; - - totalPageRef.current = Math.ceil(result.length / pageSize); - - if (isLoadingMoreRef.current) { - pageRef.current = totalPageRef.current; - } else if ( - pageRef.current === oldTotalPage && - scrollPosRef.current.pos === 'bottom' - ) { - scrollPosRef.current = { - pos: 'bottom', - page: pageRef.current - }; - pageRef.current = totalPageRef.current; - setScrollPos(['bottom', pageRef.current]); - } - - const start = (pageRef.current - 1) * pageSize; - const end = pageRef.current * pageSize; - const currentLogs = result.slice(start, end); - - setLogs(result); - setTotalPage(totalPageRef.current); - setPage(pageRef.current); - setCurrentData(currentLogs); - debounceLoading(); - }; - - return () => { - if (logParseWorker.current) { - logParseWorker.current.terminate(); - } - }; - }, []); - - return ( -
-
-
- -
- {loading && ( - - )} - {totalPage > 1 && ( -
-
- -
-
- )} -
-
- ); -}); - -export default LogsViewer; diff --git a/src/components/logs-viewer/xterm-viewer.tsx b/src/components/logs-viewer/xterm-viewer.tsx deleted file mode 100644 index cea7e1c4..00000000 --- a/src/components/logs-viewer/xterm-viewer.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import useSetChunkRequest from '@/hooks/use-chunk-request'; -import { FitAddon } from '@xterm/addon-fit'; -import { Terminal } from '@xterm/xterm'; -import '@xterm/xterm/css/xterm.css'; -import classNames from 'classnames'; -import _ from 'lodash'; -import { - forwardRef, - useEffect, - useImperativeHandle, - useRef, - useState -} from 'react'; -import { replaceLineRegex } from './config'; -import './styles/xterm-viewer.less'; -import useSize from './use-size'; - -interface LogsViewerProps { - height: number; - content?: string; - url: string; - ref?: any; - params?: object; -} -const LogsViewer: React.FC = forwardRef((props, ref) => { - const { height, content, url } = props; - const { setChunkRequest } = useSetChunkRequest(); - const chunkRequedtRef = useRef(null); - const scroller = useRef({}); - const termRef = useRef({}); - const termwrapRef = useRef({}); - const fitAddonRef = useRef({}); - const cacheDataRef = useRef(null); - const [logs, setLogs] = useState(''); - const [loading, setLoading] = useState(false); - const size = useSize(scroller); - const logParseWorker = useRef(null); - const lineCountRef = useRef(0); - - useImperativeHandle(ref, () => ({ - abort() { - chunkRequedtRef.current?.current?.abort?.(); - logParseWorker.current?.terminate?.(); - } - })); - - useEffect(() => { - logParseWorker.current?.terminate?.(); - - logParseWorker.current = new Worker( - // @ts-ignore - new URL('./parse-worker.ts', import.meta.url), - { - type: 'module' - } - ); - - logParseWorker.current.onmessage = (event: any) => { - const { result, lines } = event.data; - lineCountRef.current = lines; - // setLogs(result.join('\n')); - console.log('res+++++++++++', result); - const data = result.map((item: any) => item.content); - termRef.current?.write?.(data.join('\n')); - }; - - return () => { - if (logParseWorker.current) { - logParseWorker.current.terminate(); - } - }; - }, []); - - const throttleScroll = _.throttle(() => { - termRef.current?.scrollToBottom?.(); - }, 100); - - const debounceLoading = _.debounce(() => { - setLoading(false); - }, 200); - - const updateContent = (inputStr: string) => { - const data = inputStr.replace(replaceLineRegex, '\n'); - cacheDataRef.current = data; - setLoading(true); - logParseWorker.current.postMessage({ - inputStr: data - }); - debounceLoading(); - }; - - const fitTerm = () => { - fitAddonRef.current?.fit?.(); - }; - - const createChunkConnection = async () => { - chunkRequedtRef.current?.current?.cancel?.(); - chunkRequedtRef.current = setChunkRequest({ - url, - params: { - ...props.params, - watch: true - }, - contentType: 'text', - handler: updateContent - }); - }; - - const initTerm = () => { - termRef.current?.dispose?.(); - termRef.current = new Terminal({ - lineHeight: 1.2, - fontSize: 13, - fontFamily: - "monospace,Menlo,Courier,'Courier New',Consolas,Monaco, 'Liberation Mono'", - disableStdin: true, - convertEol: true, - theme: { - background: '#1e1e1e', - foreground: 'rgba(255,255,255,0.8)' - }, - cursorInactiveStyle: 'none', - smoothScrollDuration: 0 - }); - fitAddonRef.current = new FitAddon(); - termRef.current.loadAddon(fitAddonRef.current); - termRef.current.open(termwrapRef.current); - - // add event - // termRef.current.onLineFeed((e: any) => { - // if (cacheDataRef.current) { - // throttleScroll(); - // } - // }); - }; - - const handleResize = _.throttle(() => { - fitTerm(); - }, 100); - - useEffect(() => { - createChunkConnection(); - return () => { - chunkRequedtRef.current?.current?.cancel?.(); - }; - }, [url, props.params]); - - useEffect(() => { - if (termwrapRef.current) { - initTerm(); - } - return () => { - termRef.current?.dispose?.(); - }; - }, [termwrapRef.current]); - - useEffect(() => { - if (size) { - handleResize(); - } - }, [size]); - - useEffect(() => { - // throttleScroll(); - }, [logs]); - - return ( -
-
-
-
-
-
-
- ); -}); - -export default LogsViewer; diff --git a/src/components/markdown-viewer/code-viewer.tsx b/src/components/markdown-viewer/code-viewer.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/markdown-viewer/full-markdown.tsx b/src/components/markdown-viewer/full-markdown.tsx deleted file mode 100644 index 02cbe753..00000000 --- a/src/components/markdown-viewer/full-markdown.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { sanitizeUrl } from '@braintree/sanitize-url'; -import 'katex/dist/katex.min.css'; -import React, { useMemo } from 'react'; -import ReactMarkdown from 'react-markdown'; -import rehypeKatex from 'rehype-katex'; -import remarkBreaks from 'remark-breaks'; -import remarkGfm from 'remark-gfm'; -import remarkMath from 'remark-math'; -import styled from 'styled-components'; -import HighlightCode from '../highlight-code'; -import './index.less'; -import { escapeBrackets, escapeDollarNumber, escapeMhchem } from './utils'; - -interface FullMarkdownProps { - content: string; - theme?: 'light' | 'dark'; -} - -const Wrapper = styled.div.attrs(() => ({ - className: 'markdown-viewer' -}))``; - -const CodeViewer = (props: any) => { - const { children, className, node, theme, ...rest } = props; - const match = /language-(\w+)/.exec(className || ''); - return match ? ( - - ) : ( - - {children} - - ); -}; - -const FullMarkdown: React.FC = ({ content, theme }) => { - const escapedContent = useMemo(() => { - return escapeMhchem(escapeBrackets(escapeDollarNumber(content))); - }, [content]); - - return ( - - ; - }, - a: ({ href, children, ...props }) => ( - - {children} - - ) - }} - > - {escapedContent} - - - ); -}; - -export default FullMarkdown; diff --git a/src/components/markdown-viewer/index.less b/src/components/markdown-viewer/index.less deleted file mode 100644 index c87fbe9a..00000000 --- a/src/components/markdown-viewer/index.less +++ /dev/null @@ -1,136 +0,0 @@ -.markdown-viewer { - word-break: break-word; - line-height: 2; - font-size: var(--font-size-base); - - .hr { - border: none; - height: 1px; - background-color: var(--ant-color-split); - border-color: var(--ant-color-split); - } - - hr { - border: none; - height: 1px; - background-color: var(--ant-color-split); - border-color: var(--ant-color-split); - } - - p { - margin-bottom: 0; - } - - b { - font-weight: var(--font-weight-bold); - } - - pre { - white-space: pre-wrap; - } - - h1, - h2, - h3, - h4 { - margin-top: 1em; - } - - h1 { - font-size: 20px; - } - - h2 { - font-size: 18px; - } - - h3 { - font-size: 16px; - } - - h4, - h5, - h6 { - font-size: 14px; - } - - .hj-wrapper { - margin-top: 16px; - } - - ul { - margin-bottom: 0; - padding-left: 20px; - } - - ol { - margin-bottom: 0; - padding-left: 20px; - } - - a * { - color: inherit; - } - - table { - width: 100%; - margin-bottom: 1.2em; - font-size: var(--font-size-small); - - th { - font-weight: var(--font-weight-bold); - line-height: 1.5; - padding-inline: 6px; - border: 1px solid var(--ant-color-split); - word-break: break-word; - text-align: left !important; - } - - td { - line-height: 1.5; - padding-inline: 6px; - border: 1px solid var(--ant-color-split); - word-break: break-word; - text-align: left !important; - } - - div { - display: inline; - } - } - - a { - div { - display: inline; - } - } - - img { - max-width: 100%; - height: auto; - } - img[src^="https://img.shields.io/"], img[src*="badge.svg"] - { - margin-bottom: 6px; - width: unset; - max-width: 100%; - } - - video { - max-width: 100%; - height: auto; - border-radius: var(--border-radius-base); - } - - audio { - max-width: 100%; - height: auto; - border-radius: var(--border-radius-base); - } - - .item-token { - color: inherit; - font-size: inherit; - font-weight: inherit; - } -} diff --git a/src/components/markdown-viewer/index.tsx b/src/components/markdown-viewer/index.tsx deleted file mode 100644 index fc815d65..00000000 --- a/src/components/markdown-viewer/index.tsx +++ /dev/null @@ -1,232 +0,0 @@ -import { EyeOutlined } from '@ant-design/icons'; -import { sanitizeUrl } from '@braintree/sanitize-url'; -import { Checkbox, Image, Typography } from 'antd'; -import DOMPurify from 'dompurify'; -import { unescape } from 'lodash'; -import { TokensList, marked } from 'marked'; -import React, { Fragment, useCallback, useEffect } from 'react'; -import HighlightCode from '../highlight-code'; -import './index.less'; - -const { Text, Link, Paragraph } = Typography; - -interface MarkdownViewerProps { - content: string; - height?: string; - theme?: 'light' | 'dark'; - generateImgLink?: (src: string) => string; -} - -const dompurifyOptions = { - FORBID_TAGS: ['meta', 'style', 'script', 'iframe'], - FORBID_ATTR: ['onerror', 'onclick', 'onload', 'style', 'autoplay'] -}; - -const cleanHtml = (html: string): string => { - return DOMPurify?.sanitize?.(html, dompurifyOptions); -}; - -const MarkdownViewer: React.FC = ({ - content, - generateImgLink, - height = 'auto', - theme = 'light' -}) => { - const renderer = new marked.Renderer(); - const tokens = marked.lexer(content); - const reDefineTypes = [ - 'code', - 'link', - 'hr', - 'heading', - 'paragraph', - 'codespan', - 'strong', - 'text', - 'image', - 'em', - 'list', - 'list_item', - 'br', - 'html', - 'escape', - 'del', - 'blockquote', - 'checkbox' - // 'bibtex' - ]; - - const isValidURL = useCallback((url: string) => { - const pattern = /^(https?:\/\/|\/\/)([^\s/$.?#].[^\s]*)$/; - - return pattern.test(url); - }, []); - - const generateImgSrc = useCallback( - (url: string | null) => { - const src = sanitizeUrl(url || ''); - if (!src) { - return ''; - } - if (generateImgLink) { - return isValidURL(src) ? src : generateImgLink(src); - } - return src; - }, - [generateImgLink] - ); - - const renderItem = useCallback( - (token: any, render: any) => { - if (token.type === 'script' || token.type === 'style') { - return null; - } - - if (!reDefineTypes.includes(token.type)) { - return ( - - ); - } - let htmlstr: any = null; - let child: any = null; - if (token.tokens?.length) { - child = render?.(token.tokens as TokensList, render); - } - const text = child ? child : unescape(token.text); - - if (token.type === 'escape') { - htmlstr = text; - } - - if (token.type === 'html') { - htmlstr = ( -
- ); - } - if (token.type === 'list') { - htmlstr = token.order ? ( -
    {render?.(token.items, render)}
- ) : ( -
    {render?.(token.items, render)}
- ); - } - - if (token.type === 'list_item') { - htmlstr =
  • {text}
  • ; - } - - if (token.type === 'del') { - htmlstr = {text}; - } - - if (token.type === 'blockquote') { - htmlstr =
    {text}
    ; - } - - if (token.type === 'checkbox') { - htmlstr = ; - } - - if (token.type === 'br') { - htmlstr =
    ; - } - - if (token.type === 'em') { - htmlstr = {text}; - } - - if (token.type === 'image') { - let href = generateImgSrc(token.href); - htmlstr = ( - {token.text} - }} - /> - ); - } - if (token.type === 'text') { - htmlstr = text; - } - if (token.type === 'codespan') { - htmlstr = {text}; - } - if (token.type === 'strong') { - htmlstr = {text}; - } - if (token.type === 'heading') { - htmlstr = {text}; - } - if (token.type === 'paragraph') { - htmlstr = {text}; - } - - if (token.type === 'code') { - htmlstr = ; - } - - if (token.type === 'link') { - htmlstr = ( - - {text} - - ); - } - if (token.type === 'hr') { - htmlstr =
    ; - } - - return htmlstr; - }, - [generateImgSrc] - ); - const renderTokens = (tokens: TokensList): any => { - return tokens?.map((token: any, index: number) => { - return {renderItem(token, renderTokens)}; - }); - }; - - useEffect(() => { - if (!content) { - return; - } - const imgs = document.querySelectorAll('.markdown-viewer img'); - const links = document.querySelectorAll('.markdown-viewer a'); - links.forEach((link) => { - // set target blank for all links - link.setAttribute('target', '_blank'); - }); - imgs.forEach((img) => { - const src = img.getAttribute('src'); - img.setAttribute('src', generateImgSrc(src)); - }); - }, [content, generateImgSrc]); - - return ( - <> -
    - {renderTokens(tokens)} -
    - - ); -}; - -export default React.memo(MarkdownViewer); diff --git a/src/components/markdown-viewer/utils.ts b/src/components/markdown-viewer/utils.ts deleted file mode 100644 index a9b367a6..00000000 --- a/src/components/markdown-viewer/utils.ts +++ /dev/null @@ -1,55 +0,0 @@ -const htmlUnescapes: Record = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'" -}; - -const reEscapedHtml = /&(?:amp|lt|gt|quot|#(?:0+)?39);/g; -const reHasEscapedHtml = RegExp(reEscapedHtml.source); - -export const unescape = (str = '') => { - return reHasEscapedHtml.test(str) - ? str.replace(reEscapedHtml, (entity) => htmlUnescapes[entity] || "'") - : str; -}; - -export function escapeDollarNumber(text: string) { - let escapedText = ''; - - for (let i = 0; i < text.length; i += 1) { - let char = text[i]; - const nextChar = text[i + 1] || ' '; - - if (char === '$' && nextChar >= '0' && nextChar <= '9') { - char = '\\$'; - } - - escapedText += char; - } - - return escapedText; -} - -export function escapeBrackets(text: string) { - const pattern = - /(```[\S\s]*?```|`.*?`)|\\\[([\S\s]*?[^\\])\\]|\\\((.*?)\\\)/g; - return text.replaceAll( - pattern, - (match, codeBlock, squareBracket, roundBracket) => { - if (codeBlock) { - return codeBlock; - } else if (squareBracket) { - return `$$${squareBracket}$$`; - } else if (roundBracket) { - return `$${roundBracket}$`; - } - return match; - } - ); -} - -export function escapeMhchem(text: string) { - return text.replaceAll('$\\ce{', '$\\\\ce{').replaceAll('$\\pu{', '$\\\\pu{'); -} diff --git a/src/components/metadata-list/index.tsx b/src/components/metadata-list/index.tsx deleted file mode 100644 index 3a9045b5..00000000 --- a/src/components/metadata-list/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { MinusOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; -import Wrapper from '../label-selector/wrapper'; - -const ItemContainer = styled.div` - display: flex; - margin-bottom: 12px; - align-items: center; - justify-content: flex-start; - - .seprator { - display: flex; - flex: none; - width: 12px; - align-items: center; - justify-content: center; - color: var(--ant-color-text-tertiary); - } - - .btn { - width: 24px; - margin-left: 10px; - flex: none; - } -`; - -interface MetadataListProps { - dataList: any[]; - label: React.ReactNode; - description?: React.ReactNode; - disabled?: boolean; - btnText?: string; - styles?: { - wrapper?: React.CSSProperties; - }; - onAdd?: () => void; - onDelete?: (index: number, item: any) => void; - children?: (item: any, index: number) => React.ReactNode; -} - -const MetadataList: React.FC = ({ - dataList, - label, - description, - disabled, - btnText, - children, - onDelete, - onAdd, - styles -}) => { - return ( - - {dataList.map((item, index) => ( - - {children?.(item, index)} - {!disabled && ( - - )} - - ))} - - ); -}; - -export default MetadataList; diff --git a/src/components/modal-footer/index.tsx b/src/components/modal-footer/index.tsx deleted file mode 100644 index 5250590d..00000000 --- a/src/components/modal-footer/index.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { useIntl } from '@umijs/max'; -import { Button, Space } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -type ModalFooterProps = { - onOk?: () => void; - onCancel?: () => void; - cancelText?: string; - okText?: string; - htmlType?: 'button' | 'submit'; - okBtnProps?: any; - cancelBtnProps?: any; - loading?: boolean; - style?: React.CSSProperties; - showOkBtn?: boolean; - showCancelBtn?: boolean; - extra?: React.ReactNode; - form?: any; - description?: React.ReactNode; - styles?: { - wrapper?: React.CSSProperties; - }; -}; - -const Wrapper = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - gap: 20px; -`; - -const ModalFooter: React.FC = ({ - onOk, - onCancel, - cancelText, - okText, - okBtnProps, - cancelBtnProps, - loading, - htmlType = 'button', - style, - showOkBtn = true, - styles, - description, - extra, - showCancelBtn = true, - form -}) => { - const intl = useIntl(); - return ( - -
    {description}
    - - {showCancelBtn && ( - - )} - {extra} - {showOkBtn && ( - - )} - -
    - ); -}; - -export default ModalFooter; diff --git a/src/components/overlay-scroller/index.module.less b/src/components/overlay-scroller/index.module.less deleted file mode 100644 index 3eaa9fc0..00000000 --- a/src/components/overlay-scroller/index.module.less +++ /dev/null @@ -1,6 +0,0 @@ -.wrapper { - overflow-y: auto; - width: 100%; - padding-inline-start: 8px; - padding-inline-end: 8px; -} diff --git a/src/components/overlay-scroller/index.tsx b/src/components/overlay-scroller/index.tsx deleted file mode 100644 index e4fbcfc1..00000000 --- a/src/components/overlay-scroller/index.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import useOverlayScroller, { - OverlayScrollerOptions -} from '@/hooks/use-overlay-scroller'; -import { Tooltip, TooltipProps } from 'antd'; -import classNames from 'classnames'; -import React from 'react'; -import s from './index.module.less'; - -// export OverlayScrollerOptions -export type { OverlayScrollerOptions }; - -export const OverlayScroller: React.FC< - OverlayScrollerOptions & { - maxHeight?: number | string; - style?: React.CSSProperties; - styles?: { - wrapper?: React.CSSProperties; - }; - children: React.ReactNode; - onScroll?: (e: React.UIEvent) => void; - } -> = ({ - children, - maxHeight, - scrollbars, - oppositeTheme, - style, - styles, - onScroll -}) => { - const scroller = React.useRef(null); - const { initialize } = useOverlayScroller({ - options: { - scrollbars, - oppositeTheme - } - }); - - React.useEffect(() => { - if (scroller.current) { - initialize(scroller.current); - } - }, []); - - return ( - - ); -}; - -/** - * - * @param maxHeight: use for scrollbars - * @param theme: because this component is used for tooltip, so the default theme always is light - * @returns - */ -export const TooltipOverlayScroller: React.FC< - OverlayScrollerOptions & { - maxHeight?: number; - title?: React.ReactNode; - children: React.ReactNode; - toolTipProps?: TooltipProps; - } -> = ({ - children, - maxHeight, - title, - toolTipProps, - scrollbars, - oppositeTheme -}) => { - const { styles, ...rest } = toolTipProps || {}; - return ( - - {title} - - ) - } - {...rest} - > - {children} - - ); -}; - -export default OverlayScroller; diff --git a/src/components/page-tools/filters-button.less b/src/components/page-tools/filters-button.less deleted file mode 100644 index 5dcb0fd2..00000000 --- a/src/components/page-tools/filters-button.less +++ /dev/null @@ -1,47 +0,0 @@ -.wrapper { - display: flex; - align-items: center; - gap: 8px; - cursor: pointer; - - .count { - display: flex; - width: 16px; - height: 16px; - justify-content: center; - align-items: center; - border-radius: 50%; - font-size: 12px; - font-weight: 500; - background-color: var(--ant-color-bg-text-active); - color: var(--ant-color-text-secondary); - } -} - -.buttonWrapper { - display: flex; - align-items: center; - justify-content: center; - position: relative; - - .close-btn { - border-radius: 50%; - color: var(--ant-color-text-quaternary); - display: none; - font-size: 16px; - - &:hover { - color: var(--ant-color-text-tertiary); - } - } - - &:hover { - .count { - display: none; - } - - .close-btn { - display: block; - } - } -} diff --git a/src/components/page-tools/index.less b/src/components/page-tools/index.less deleted file mode 100644 index 6420c778..00000000 --- a/src/components/page-tools/index.less +++ /dev/null @@ -1,18 +0,0 @@ -.page-tools { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 70px; - - .left { - display: flex; - align-items: center; - font-size: var(--font-size-middle); - } - - .right { - display: flex; - align-items: center; - font-size: var(--font-size-middle); - } -} diff --git a/src/components/page-tools/index.tsx b/src/components/page-tools/index.tsx deleted file mode 100644 index d3cd338f..00000000 --- a/src/components/page-tools/index.tsx +++ /dev/null @@ -1,278 +0,0 @@ -import DropDownActions from '@/components/drop-down-actions'; -import { - CloseCircleFilled, - DeleteOutlined, - DownOutlined, - PlusOutlined, - SearchOutlined, - SyncOutlined -} from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Input, Space } from 'antd'; -import React, { useMemo } from 'react'; -import IconFont from '../icon-font'; -import BaseSelect from '../seal-form/base/select'; -import filtersButtonCss from './filters-button.less'; -import './index.less'; - -type PageToolsProps = { - left?: React.ReactNode; - right?: React.ReactNode; - marginBottom?: number; - marginTop?: number; - style?: React.CSSProperties; -}; - -export const FiltersButton = ({ - onClick, - onClear, - count -}: { - onClick: () => void; - onClear: () => void; - count?: number; -}) => { - const handleClear = (e: React.MouseEvent) => { - e.stopPropagation(); - onClear(); - }; - const intl = useIntl(); - - return ( -
    - -
    - ); -}; - -const PageTools: React.FC = (props) => { - const { - left, - right, - marginBottom = 0, - marginTop = 30, - style: pageStyle - } = props; - - const newStyle: React.CSSProperties = useMemo(() => { - const style: React.CSSProperties = {}; - style.marginBottom = `${marginBottom}px`; - style.marginTop = `${marginTop}px`; - if (pageStyle) { - Object.assign(style, pageStyle); - } - return style; - }, [marginBottom, marginTop, pageStyle]); - - return ( -
    -
    {left}
    -
    {right}
    -
    - ); -}; - -interface ActionItem { - label: string; - locale: boolean; - value: string; - key: string; - icon: React.ReactNode; - [key: string]: any; -} - -interface FilterBarProps { - handleInputChange: (e: React.ChangeEvent) => void; - handleSelectChange?: (value: any) => void; - handleSearch: () => void; - handleDeleteByBatch?: () => void; - handleClickPrimary?: (item: any) => void; - rowSelection?: any; - actionItems?: ActionItem[]; - selectOptions?: Global.BaseOption[]; - showSelect?: boolean; - buttonText?: string; - buttonIcon?: React.ReactNode; - marginBottom?: number; - marginTop?: number; - inputHolder?: string; - selectHolder?: string; - actionType?: 'dropdown' | 'button'; - showPrimaryButton?: boolean; - showDeleteButton?: boolean; - right?: React.ReactNode; - left?: React.ReactNode; - filtersButtonProps?: { - show: boolean; - count: number; - onClick: () => void; - onClear: () => void; - }; - select?: { - showSearch?: boolean; - }; - widths?: { - input?: number; - select?: number; - }; -} - -export const FilterBar: React.FC = (props) => { - const { - handleInputChange, - handleSelectChange, - handleSearch, - handleDeleteByBatch = null, - handleClickPrimary = null, - rowSelection, - actionItems = [], - selectOptions, - showSelect, - buttonText, - buttonIcon, - select, - actionType = 'button', - marginBottom = 10, - marginTop = 10, - inputHolder, - selectHolder, - right, - left, - widths, - filtersButtonProps - } = props; - const intl = useIntl(); - - const renderLeft = () => { - return ( - - {filtersButtonProps?.show && ( - - )} - - } - placeholder={ - inputHolder || - intl.formatMessage({ - id: 'common.filter.name' - }) - } - style={{ width: widths?.input || 230 }} - allowClear - onChange={handleInputChange} - > - {showSelect && ( - - )} - - - ); - }; - - const renderRight = () => { - if (!handleClickPrimary && !handleDeleteByBatch) { - return null; - } - return ( - - {handleClickPrimary ? ( - actionType === 'dropdown' ? ( - - - - ) : ( - - ) - ) : null} - {handleDeleteByBatch && ( - - )} - - ); - }; - - return ( - - ); -}; - -export default PageTools; diff --git a/src/components/popover/index.less b/src/components/popover/index.less deleted file mode 100644 index a83ddd77..00000000 --- a/src/components/popover/index.less +++ /dev/null @@ -1,27 +0,0 @@ -:local(.seal_custom_popover) { - position: relative; - padding-top: var(--ant-popover-inner-padding); - border-radius: var(--ant-border-radius-lg); - background-color: var(--color-white-1); - box-shadow: var(--ant-box-shadow-secondary); - overflow: hidden; - padding-top: 80px; - :global(.ant-popover-inner) { - box-shadow: none; - padding-top: 0; - } - :global(.ant-popover-content) { - position: static; - } - :global(.ant-popover-title) { - position: absolute; - top: 0; - padding-block: var(--ant-popover-inner-padding) - var(--ant-popover-title-margin-bottom); - margin-bottom: 0; - background: #fff; - padding-left: var(--ant-popover-inner-padding); - left: 0; - width: 100%; - } -} diff --git a/src/components/popover/index.tsx b/src/components/popover/index.tsx deleted file mode 100644 index 99de6674..00000000 --- a/src/components/popover/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Popover } from 'antd'; -import type { PopoverProps } from 'antd/lib/popover'; -import classNames from 'classnames'; -import styles from './index.less'; - -const SealPopover: React.FC = (props) => { - const { className, children, style, ...restProps } = props; - - return ( -
    - - {children} - -
    - ); -}; - -export default SealPopover; diff --git a/src/components/progress-bar/index.tsx b/src/components/progress-bar/index.tsx deleted file mode 100644 index 46bba1d2..00000000 --- a/src/components/progress-bar/index.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Progress, Tooltip } from 'antd'; -import React, { memo, useEffect, useMemo } from 'react'; - -const RenderProgress = memo( - (props: { - defaultOpen?: boolean; - percent: number; - steps?: number; - download?: boolean; - label?: React.ReactNode; - successPercent?: number; - successColor?: string; - }) => { - const { defaultOpen, percent, download, label, successPercent } = props; - const [open, setOpen] = React.useState(false); - - const strokeColor = useMemo(() => { - if (download) { - return 'var(--ant-color-primary)'; - } - - if (percent <= 50) { - return 'var(--ant-color-success)'; - } - if (percent <= 80) { - return 'var(--ant-color-warning)'; - } - return 'var(--ant-color-error)'; - }, [percent]); - - useEffect(() => { - setOpen(defaultOpen || false); - }, [defaultOpen]); - - const renderProgress = useMemo(() => { - return ( - { - return ( - - {percent}% - - ); - }} - percent={percent} - success={{ - percent: successPercent, - strokeColor: 'var(--ant-geekblue-3)' - }} - strokeColor={strokeColor} - > - ); - }, [percent, successPercent, strokeColor]); - - return ( - <> - {label ? ( - - {renderProgress} - - ) : ( - renderProgress - )} - - ); - } -); - -export default RenderProgress; diff --git a/src/components/radio-buttons/index.less b/src/components/radio-buttons/index.less deleted file mode 100644 index ee4bed59..00000000 --- a/src/components/radio-buttons/index.less +++ /dev/null @@ -1,21 +0,0 @@ -.radio-button-wrap { - .item { - display: flex; - justify-content: center; - align-items: center; - font-size: var(--font-size-base); - border-radius: var(--border-radius-base); - height: 32px; - padding: 0 8px; - border: 1px solid var(--ant-color-border); - cursor: pointer; - - &.active { - background-color: var(--ant-color-fill-secondary); - } - - &:hover { - background-color: var(--ant-color-fill-secondary); - } - } -} diff --git a/src/components/radio-buttons/index.tsx b/src/components/radio-buttons/index.tsx deleted file mode 100644 index c228b9ee..00000000 --- a/src/components/radio-buttons/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Space } from 'antd'; -import classNames from 'classnames'; -import React from 'react'; -import './index.less'; - -interface RadioButtonsProps { - options: { value: any; label: React.ReactNode }[]; - value: string; - gap?: number; - onChange: (value: string) => void; -} -const RadioButtons: React.FC = (props) => { - const { options, value, onChange, gap = 12 } = props; - return ( - - {options.map((option) => ( - onChange({ target: { value: option.value } } as any)} - className={classNames('item', { active: value === option.value })} - > - {option.label} - - ))} - - ); -}; - -export default RadioButtons; diff --git a/src/components/resize-container/index.tsx b/src/components/resize-container/index.tsx deleted file mode 100644 index a45df56b..00000000 --- a/src/components/resize-container/index.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Col, Row } from 'antd'; -import ResizeObserver from 'rc-resize-observer'; -import useResponsive from './use-responsive'; - -interface ResizeObserverContainerProps { - dataList: any[]; - renderItem: (data: any) => React.ReactNode; - defaultSpan?: number; - resizable?: boolean; -} - -const ResizeContainer: React.FC = ({ - defaultSpan = 8, - dataList, - renderItem, - resizable = true -}) => { - const { span, handleResize } = useResponsive({ defaultSpan }); - - return ( - - - {dataList.map((item: any, index) => { - return ( - - {renderItem(item)} - - ); - })} - - - ); -}; - -export default ResizeContainer; diff --git a/src/components/resize-container/use-responsive.ts b/src/components/resize-container/use-responsive.ts deleted file mode 100644 index 81a0ef0b..00000000 --- a/src/components/resize-container/use-responsive.ts +++ /dev/null @@ -1,23 +0,0 @@ -import breakpoints from '@/config/breakpoints'; -import { useMemoizedFn } from 'ahooks'; -import _ from 'lodash'; -import { useState } from 'react'; - -const useResponsive = ({ defaultSpan = 8 }: { defaultSpan?: number }) => { - const [span, setSpan] = useState(defaultSpan); - - const getSpanByWidth = (width: number) => { - if (width < breakpoints.md) return 24; - if (width < breakpoints.lg) return 12; - return 8; - }; - - const handleResize = useMemoizedFn( - _.throttle((size: { width: number; height: number }) => { - setSpan(getSpanByWidth(size.width)); - }, 100) - ); - return { span, handleResize }; -}; - -export default useResponsive; diff --git a/src/components/scroller-modal/gs-drawer.tsx b/src/components/scroller-modal/gs-drawer.tsx deleted file mode 100644 index 1d7163a9..00000000 --- a/src/components/scroller-modal/gs-drawer.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { useEscHint } from '@/hooks/use-esc-hint'; -import { CloseOutlined } from '@ant-design/icons'; -import { Button, Drawer, type DrawerProps } from 'antd'; -import React from 'react'; - -/** - * use ColumnWrapper to wrap content in Drawer with scroller - * 57px is the height of header - * @param props - * @returns - */ -const ScrollerModal = (props: DrawerProps) => { - const { title, closable = true, mask, styles, ...restProps } = props; - const { EscHint } = useEscHint({ - enabled: !props.keyboard && props.open - }); - const handleCancel = (e: React.MouseEvent) => { - props.onClose?.(e); - }; - - return ( - <> - - - {title} - - {closable && ( - - )} -
    - } - > - {restProps.children} - {EscHint} - - - ); -}; - -export default ScrollerModal; diff --git a/src/components/scroller-modal/index.tsx b/src/components/scroller-modal/index.tsx deleted file mode 100644 index ecee9e3e..00000000 --- a/src/components/scroller-modal/index.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import useBodyScroll from '@/hooks/use-body-scroll'; -import useOverlayScroller from '@/hooks/use-overlay-scroller'; -import { Modal, type ModalProps } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; -import { ScrollerContext } from './use-scroller-context'; - -const Wrapper = styled.div<{ $maxHeight?: number | string }>` - max-height: ${({ $maxHeight }) => - typeof $maxHeight === 'number' ? `${$maxHeight}px` : $maxHeight}; - overflow-y: auto; - width: 100%; -`; - -const Title = styled.div` - display: flex; - align-items: center; - max-width: 360px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -`; - -const ScrollerModal = ( - props: ModalProps & { maxContentHeight?: number | string } -) => { - const scroller = React.useRef(null); - const { saveScrollHeight, restoreScrollHeight } = useBodyScroll(); - const { initialize, destroyInstance, scrollToBottom } = useOverlayScroller(); - - React.useEffect(() => { - if (props.open) { - saveScrollHeight(); - } else { - restoreScrollHeight(); - } - }, [props.open]); - - // init scroller, delay to ensure modal is fully open - React.useEffect(() => { - let timeout = null; - if (props.open) { - timeout = setTimeout(() => { - if (scroller.current) { - initialize(scroller.current); - } - }, 100); - } - return () => { - if (timeout) { - clearTimeout(timeout); - } - destroyInstance(); - }; - }, [props.open, initialize]); - - return ( - {props.title}} - destroyOnHidden={true} - styles={{ - container: { - padding: 0 - }, - header: { - padding: 'var(--ant-modal-content-padding)', - paddingBottom: '0' - }, - body: { - padding: '0', - paddingBlockEnd: props.footer ? '0' : '24px' - }, - footer: props.footer - ? { - padding: '12px 24px 24px', - margin: '0' - } - : {} - }} - > - - - - - ); -}; - -export default ScrollerModal; diff --git a/src/components/scroller-modal/use-scroller-context.ts b/src/components/scroller-modal/use-scroller-context.ts deleted file mode 100644 index 6e8b6dff..00000000 --- a/src/components/scroller-modal/use-scroller-context.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createContext, useContext } from 'react'; - -interface ScrollerContextProps { - scrollToBottom: () => void; -} - -export const ScrollerContext = createContext({ - scrollToBottom: () => {} -}); - -export const useScrollerContext = () => useContext(ScrollerContext); diff --git a/src/components/seal-form/auto-complete.tsx b/src/components/seal-form/auto-complete.tsx deleted file mode 100644 index 77c674f8..00000000 --- a/src/components/seal-form/auto-complete.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons'; -import { AutoComplete, Form, Typography } from 'antd'; -import type { AutoCompleteProps } from 'antd/lib'; -import React, { useEffect, useRef, useState } from 'react'; -import { LoadingContent } from './components/not-found-content'; -import { SealFormItemProps } from './types'; -import Wrapper from './wrapper'; -import SelectWrapper from './wrapper/select'; - -const Link = Typography.Link; - -const SealAutoComplete: React.FC< - AutoCompleteProps & - SealFormItemProps & { - onPaste?: (e: any) => void; - onInput?: (e: Event) => void; - clearSpaceOnBlur?: boolean; - } -> = (props) => { - const { - label, - placeholder, - required, - description, - isInFormItems = true, - trim = true, - onSelect, - onBlur, - checkStatus, - extra, - style, - addAfter, - suffixIcon, - loading, - allowClear, - clearSpaceOnBlur, - showSearch, - ...rest - } = props; - const [isFocus, setIsFocus] = useState(false); - const inputRef = useRef(null); - let status = ''; - if (isInFormItems) { - const statusData = Form?.Item?.useStatus?.(); - status = statusData?.status || ''; - } - - useEffect(() => { - if (props.value) { - setIsFocus(true); - } - }, [props.value]); - - const handleClickWrapper = () => { - if (!props.disabled && !isFocus) { - inputRef.current?.focus?.(); - setIsFocus(true); - } - }; - - const handleChange = (val: string, option: any) => { - console.log('handleChange val:', val); - let value = val; - if (trim) { - value = value?.trim?.(); - } - props.onChange?.(value, option); - }; - - const handleOnFocus = (e: any) => { - setIsFocus(true); - props.onFocus?.(e); - }; - - const handleOnBlur = (e: any) => { - if (!props.value) { - setIsFocus(false); - } - - if (clearSpaceOnBlur) { - e.target.value = e.target.value?.replace(/\s+/g, ''); - props.onChange?.(e.target.value); - } else { - e.target.value = e.target.value?.trim(); - } - props.onBlur?.(e); - }; - - const handleOnSelect = (value: any, option: any) => { - onSelect?.(value, option); - }; - - const handleOnInput = (e: any) => { - if (trim) { - e.target.value = e.target.value?.trim(); - } - props.onInput?.(e); - }; - - const renderAfter = () => { - if (loading) { - return ( - - - - ); - } - return suffixIcon || null; - }; - - const popupRender = (originNode: React.ReactElement): React.ReactElement => { - if (loading) { - return ; - } - return originNode || null; - }; - - return ( - - - {placeholder} - ) : ( - '' - ) - } - allowClear={!loading && allowClear} - suffixIcon={renderAfter()} - // @ts-ignore - status={checkStatus || status} - onSelect={handleOnSelect} - onFocus={handleOnFocus} - onBlur={handleOnBlur} - showSearch={showSearch} - onChange={handleChange} - popupRender={popupRender} - onInput={handleOnInput} - onPaste={props.onPaste} - > - - - ); -}; - -export default SealAutoComplete; diff --git a/src/components/seal-form/base/select.tsx b/src/components/seal-form/base/select.tsx deleted file mode 100644 index 0fe0b72b..00000000 --- a/src/components/seal-form/base/select.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import IconFont from '@/components/icon-font'; -import type { SelectProps } from 'antd'; -import { Select } from 'antd'; -import React, { forwardRef, useImperativeHandle } from 'react'; -import NotFoundContent from '../components/not-found-content'; -import SelectCss from './styles.less'; - -const BaseSelect: React.FC< - SelectProps & { ref?: any; footer?: React.ReactNode } -> = forwardRef((props, ref) => { - const { notFoundContent, loading, ...restProps } = props; - const [isFocus, setIsFocus] = React.useState(false); - const inputRef = React.useRef(null); - - useImperativeHandle(ref, () => ({ - ...(inputRef.current || ({} as any)) - })); - - const handleFocus = (e: React.FocusEvent) => { - setIsFocus(true); - props.onFocus?.(e); - }; - const handleBlur = (e: React.FocusEvent) => { - setIsFocus(false); - props.onBlur?.(e); - }; - const renderSuffixIcon = () => { - if (props.suffixIcon) { - return props.suffixIcon; - } - if (!props.showSearch) { - return ; - } - return !isFocus ? : undefined; - }; - - return ( - -
    - - ); -}; - -export default { - TextArea: SealTextArea, - Input: SealInput, - Password: SealPassword, - Number: SealInputNumber, - Search: SealInputSearch -} as Record< - string, - React.FC ->; diff --git a/src/components/seal-form/seal-select.tsx b/src/components/seal-form/seal-select.tsx deleted file mode 100644 index cf02c4f3..00000000 --- a/src/components/seal-form/seal-select.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { isNotEmptyValue } from '@/utils/index'; -import { useIntl } from '@umijs/max'; -import type { SelectProps } from 'antd'; -import { Form } from 'antd'; -import { cloneDeep } from 'lodash'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import BaseSelect from './base/select'; -import NotFoundContent from './components/not-found-content'; -import { SealFormItemProps } from './types'; -import Wrapper from './wrapper'; -import SelectWrapper from './wrapper/select'; - -const SealSelect: React.FC< - SelectProps & - SealFormItemProps & { footer?: React.ReactNode; alwaysFocus?: boolean } -> = (props) => { - const { - label, - placeholder, - children, - required, - description, - options, - allowNull, - isInFormItems = true, - notFoundContent = null, - loading, - footer, - alwaysFocus = false, - styles, - ...rest - } = props; - const intl = useIntl(); - const [isFocus, setIsFocus] = useState(false); - const inputRef = useRef(null); - - let status = ''; - - // the status can be controlled by Form.Item - if (isInFormItems) { - const statusData = Form?.Item?.useStatus?.(); - status = statusData?.status || ''; - } else { - status = props.status || ''; - } - - const _options = useMemo(() => { - if (!options?.length) { - return []; - } - const list = cloneDeep(options); - return list.map((item: any) => { - if (item.locale) { - item.label = intl.formatMessage({ id: item.label as string }); - } - return item; - }); - }, [options, intl]); - - useEffect(() => { - if ( - isNotEmptyValue(props.value) || - (allowNull && (props.value === null || props.value === undefined)) - ) { - setIsFocus(true); - } - }, [props.value, allowNull]); - - const handleClickWrapper = () => { - if (!props.disabled && !isFocus) { - inputRef.current?.focus?.(); - setIsFocus(true); - } - }; - - const handleChange = (val: any, options: any) => { - if (isNotEmptyValue(val) || (allowNull && val === null)) { - setIsFocus(true); - } else { - setIsFocus(false); - } - props.onChange?.(val || null, options); - }; - - const handleOnFocus = (e: any) => { - setIsFocus(true); - props.onFocus?.(e); - }; - - const handleOnBlur = (e: any) => { - if (allowNull && props.value === null) { - setIsFocus(true); - } else if (!props.value) { - setIsFocus(false); - } - props.onBlur?.(e); - }; - - return ( - - - - } - > - {children} - - - - ); -}; - -export default SealSelect; diff --git a/src/components/seal-form/seal-slider.tsx b/src/components/seal-form/seal-slider.tsx deleted file mode 100644 index 5a74c056..00000000 --- a/src/components/seal-form/seal-slider.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { INPUT_WIDTH } from '@/constants'; -import { Form, InputNumber, Slider, type SliderSingleProps } from 'antd'; -import React from 'react'; -import LabelInfo from './components/label-info'; -import Wrapper from './wrapper'; -import SliderWrapper from './wrapper/slider'; - -interface SealSliderProps extends SliderSingleProps { - required?: boolean; - label?: React.ReactNode; - labelWidth?: number | string; - description?: string; - isInFormItems?: boolean; - inputnumber?: boolean; - checkStatus?: 'success' | 'error' | 'warning' | ''; -} - -const SealSlider: React.FC = (props) => { - const { - label, - value, - required, - description, - isInFormItems = true, - max, - min, - step, - defaultValue, - checkStatus, - inputnumber = false, - labelWidth, - tooltip = { open: false }, - ...rest - } = props; - - let status = ''; - if (isInFormItems) { - const statusData = Form?.Item?.useStatus?.(); - status = statusData?.status || ''; - } - - const handleChange = (value: number) => { - props.onChange?.(value); - }; - - const handleInput = (value: number | null) => { - const newValue = value || 0; - props.onChange?.(newValue); - }; - - const renderLabel = () => { - return ( - - - - {inputnumber ? ( - - ) : ( - {value} - )} - - ); - }; - return ( - - - - - - ); -}; - -export default SealSlider; diff --git a/src/components/seal-form/seal-switch.tsx b/src/components/seal-form/seal-switch.tsx deleted file mode 100644 index b7f24f59..00000000 --- a/src/components/seal-form/seal-switch.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Form, Switch, type SwitchProps } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; -import LabelInfo from './components/label-info'; -import Wrapper from './wrapper'; - -const Inner = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - padding-inline: 14px; - .ant-switch { - margin-top: 0 !important; - } -`; - -interface SealSwitchProps extends SwitchProps { - required?: boolean; - label?: React.ReactNode; - labelWidth?: number | string; - description?: string; - isInFormItems?: boolean; - checkStatus?: 'success' | 'error' | 'warning' | ''; -} - -const SealSlider: React.FC = (props) => { - const { - label, - value, - required, - description, - isInFormItems = true, - defaultValue, - checkStatus, - labelWidth, - size = 'small', - ...rest - } = props; - - let status = ''; - if (isInFormItems) { - const statusData = Form?.Item?.useStatus?.(); - status = statusData?.status || ''; - } - - const handleChange = (value: boolean, event: any) => { - props.onChange?.(value, event); - }; - - return ( - - - - - - - ); -}; - -export default SealSlider; diff --git a/src/components/seal-form/seal-textarea.tsx b/src/components/seal-form/seal-textarea.tsx deleted file mode 100644 index c0e9f357..00000000 --- a/src/components/seal-form/seal-textarea.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import { Form, Input } from 'antd'; -import type { TextAreaProps } from 'antd/es/input/TextArea'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import styled from 'styled-components'; -import { SealFormItemProps } from './types'; -import Wrapper from './wrapper'; -import InputWrapper from './wrapper/input'; - -const LabelWrapper = styled.div.attrs({ - className: 'seal-textarea-label' -})` - display: flex; - align-items: center; - justify-content: flex-start; - padding-bottom: 2px; - background-color: var(--ant-color-bg-container); -`; - -interface InputTextareaProps extends TextAreaProps { - scaleSize?: boolean; - alwaysFocus?: boolean; // it's order to display the placeholder -} - -const SealTextArea: React.FC = ( - props -) => { - const { - label, - placeholder, - onChange, - onFocus, - onBlur, - onInput, - style, - required, - isInFormItems = true, - description, - variant, - extra, - addAfter, - trim, - scaleSize, - alwaysFocus, - ...rest - } = props; - const [isFocus, setIsFocus] = useState(false); - const inputRef = useRef(null); - let status = ''; - if (isInFormItems) { - const statusData = Form?.Item?.useStatus?.(); - status = statusData?.status || ''; - } - - useEffect(() => { - if (props.value) { - setIsFocus(true); - } - }, [props.value]); - - const autoSize = useMemo(() => { - const focusRows = props.autoSize || { minRows: 2, maxRows: 5 }; - - if (scaleSize) { - return isFocus ? focusRows : { minRows: 1, maxRows: 1 }; - } - - return focusRows; - }, [props.autoSize, isFocus, scaleSize]); - - const handleClickWrapper = () => { - if (!props.disabled && !isFocus) { - inputRef.current?.focus?.({ - cursor: 'all' - }); - setIsFocus(true); - } - }; - - const handleChange = (e: any) => { - onChange?.(e); - }; - - const handleOnFocus = (e: any) => { - setIsFocus(true); - onFocus?.(e); - }; - - const handleOnBlur = (e: any) => { - if (!inputRef.current?.resizableTextArea?.textArea?.value) { - setIsFocus(false); - } - onBlur?.(e); - }; - - const handleInput = (e: any) => { - onInput?.(e); - }; - - return ( - - {label}} - isFocus={alwaysFocus || isFocus} - required={required} - description={description} - className="seal-textarea-wrapper" - extra={extra} - disabled={props.disabled} - addAfter={addAfter} - onClick={handleClickWrapper} - > - handleChange(e)} - > - - - ); -}; - -export default SealTextArea; diff --git a/src/components/seal-form/simple-select.tsx b/src/components/seal-form/simple-select.tsx deleted file mode 100644 index 9e4754a9..00000000 --- a/src/components/seal-form/simple-select.tsx +++ /dev/null @@ -1,308 +0,0 @@ -import { useIntl } from '@umijs/max'; -import type { SelectProps } from 'antd'; -import { Checkbox, Tag } from 'antd'; -import { CheckboxChangeEvent } from 'antd/es/checkbox'; -import React, { forwardRef, useEffect, useImperativeHandle } from 'react'; -import styled from 'styled-components'; -import AutoTooltip from '../auto-tooltip'; -import BaseSelect from './base/select'; - -const OptionWrapper = styled.div` - display: flex; - align-items: center; - gap: 8px; -`; - -const DropdownWrapper = styled.div` - .ant-select-item { - padding-inline-start: 8px; - &:hover { - background-color: var(--ant-select-option-active-bg); - } - } - .ant-select-item-option-selected:not(.ant-select-item-option-disabled) { - background-color: unset; - font-weight: unset; - &:hover { - background-color: var(--ant-select-option-active-bg); - } - } -`; - -const SelectAllWrapper = styled.div` - margin-bottom: 10px; - padding: 5px 8px; - font-size: 12px; - border-bottom: 1px solid var(--ant-color-split); - .ant-checkbox-wrapper { - color: var(--ant-color-text-tertiary); - } -`; - -const TagWrapper = styled(Tag)` - border-radius: 12px; -`; - -const SimpleSelect: React.FC< - SelectProps & { - ref?: any; - showTags?: boolean; - optionLabelRender?: (option: any) => React.ReactNode; - styles?: { - wrapper?: React.CSSProperties; - select?: React.CSSProperties; - }; - } -> = forwardRef((props, ref) => { - const intl = useIntl(); - const { - options = [], - showTags: tagsVisible, - styles = {}, - optionLabelRender, - maxTagCount: tagCount, - ...restProps - } = props; - - const [allSelection, setAllSelection] = React.useState<{ - checked: boolean; - indeterminate: boolean; - }>({ - checked: false, - indeterminate: false - }); - const [optionsList, setOptionsList] = React.useState(options || []); - const selectRef = React.useRef(null); - const selectorRef = React.useRef(null); - - const showTags = Array.isArray(props.value) && props.value.length === 1; - const maxTagCount = - Array.isArray(props.value) && props.value.length === 1 ? 1 : 0; - - useEffect(() => { - setOptionsList(options || []); - }, [options]); - - const optionRender = (option: any, info: any) => { - const { value, label } = option; - return ( - - {restProps.value?.includes?.(value) ? ( - - ) : ( - - )} - - {optionLabelRender ? optionLabelRender(option) : label} - - - ); - }; - - const handleOnCheckboxChange = (e: CheckboxChangeEvent) => { - const isChecked = e.target.checked; - const allValues = optionsList?.map((opt: any) => opt.value) || []; - - setAllSelection({ - checked: isChecked, - indeterminate: false - }); - - let allSelectedValues = [...(restProps.value || [])]; - - if (isChecked) { - // Select all options - allSelectedValues = Array.from( - new Set([...allSelectedValues, ...allValues]) - ); - } else { - // Deselect all options - allSelectedValues = allSelectedValues.filter( - (value) => !allValues.includes(value) - ); - } - - restProps.onChange?.(allSelectedValues, optionsList || []); - }; - - const dropdownRender = (originPanel: React.ReactNode) => { - return ( - - {restProps.mode === 'multiple' && ( - - - {intl.formatMessage({ id: 'common.checkbox.all' })} - - - )} - {originPanel} - - ); - }; - - const handleOnChange = (value: any, option: any) => { - const selectedValues = Array.isArray(value) ? value : [value]; - const allSelected = optionsList?.map((opt: any) => opt.value) || []; - const isAllSelected = selectedValues.length === allSelected?.length; - - setAllSelection({ - checked: isAllSelected, - indeterminate: !isAllSelected && selectedValues.length > 0 - }); - - restProps.onChange?.(selectedValues, option); - }; - - const filterOption = (inputValue: string, option: any) => { - if (!option || !option.label) return false; - return option.label.toLowerCase().includes(inputValue.toLowerCase()); - }; - - const checkAllSelection = (list: Global.BaseOption[]) => { - if ( - !restProps.value || - !Array.isArray(restProps.value) || - list.length === 0 - ) { - setAllSelection({ - checked: false, - indeterminate: false - }); - return; - } - const selectedValues = new Set(restProps.value); - const allValues = list?.map((opt: any) => opt.value) || []; - - const isAllSelected = allValues.every((val: any) => - selectedValues.has(val) - ); - - const isSomeSelected = allValues.some((val: any) => - selectedValues.has(val) - ); - - setAllSelection({ - checked: isAllSelected, - indeterminate: isSomeSelected && !isAllSelected - }); - }; - - const TagRender = (props: any) => { - const { label } = props; - const count = props.isMaxTag ? label.slice(0, -3).slice(1) : label; - - return ( - - {showTags - ? label - : intl.formatMessage({ id: 'common.select.count' }, { count: count })} - - ); - }; - - const handleOnSearch = (value: string) => { - if (restProps.showSearch?.onSearch) { - restProps.showSearch?.onSearch?.(value); - } else { - const filteredOptions = options?.filter((option: any) => - option.label.toLowerCase().includes(value.toLowerCase()) - ) as Global.BaseOption[]; - setOptionsList(filteredOptions || []); - checkAllSelection(filteredOptions || []); - } - }; - - const handleOnBlur = (e: any) => { - restProps.onBlur?.(e); - }; - - const handleOnFocus = (e: any) => { - restProps.onFocus?.(e); - }; - - const handleOnOpenChange = (open: boolean) => { - if (!open) { - checkAllSelection(options as Global.BaseOption[]); - setOptionsList(options || []); - } - }; - - useEffect(() => { - const input = selectRef.current?.querySelector?.('input'); - - if (!input) return; - - const handler = (event: KeyboardEvent) => { - if ( - event.key === 'Backspace' && - (input as HTMLInputElement).value === '' - ) { - event.stopPropagation(); - event.preventDefault(); - } - }; - - input.addEventListener('keydown', handler); - - return () => { - input.removeEventListener('keydown', handler); - }; - }, [selectRef.current]); - - useImperativeHandle(ref, () => ({ - focus: () => { - selectorRef.current?.focus(); - }, - blur: () => { - selectorRef.current?.blur(); - } - })); - - return ( -
    - - {props.children} - -
    - ); -}); - -export default SimpleSelect; diff --git a/src/components/seal-form/styles/row-textarea.less b/src/components/seal-form/styles/row-textarea.less deleted file mode 100644 index c9794d48..00000000 --- a/src/components/seal-form/styles/row-textarea.less +++ /dev/null @@ -1,138 +0,0 @@ -.row-textarea-wrapper { - position: relative; - - .actions-wrapper { - display: none; - position: absolute; - right: 6px; - bottom: 50%; - transform: translateY(50%); - gap: 8px; - z-index: 10; - align-items: center; - justify-content: flex-end; - } - - .actions { - display: flex; - gap: 4px; - align-items: center; - border-radius: var(--ant-border-radius); - } - - &.show { - display: flex; - bottom: 8px; - transform: unset; - } - - &:hover { - .actions-wrapper { - display: flex; - } - } - - &.dropDownOpen { - .actions-wrapper { - display: flex; - } - } - - &.from-url { - .actions-wrapper { - display: flex; - } - } - - &.expanded { - .actions-wrapper { - display: flex; - bottom: 8px; - transform: unset; - } - } -} - -.row-textarea { - position: relative; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0; - overflow: hidden; - cursor: pointer; - transition: background-color 0.3s ease; - border-radius: var(--border-radius-base); - border: 1px solid var(--ant-color-border); - - .textarea-wrapper { - flex: 1; - width: 100%; - } - - &:hover { - &::before { - content: ''; - display: flex; - position: absolute; - left: 0; - bottom: 0; - right: 0; - top: 0; - background-color: var(--ant-color-fill-tertiary); - z-index: 5; - pointer-events: none; - } - } - - &:focus-within { - background-color: transparent; - - &::before { - background-color: transparent; - } - } - - .content-wrap { - position: relative; - display: flex; - align-items: center; - justify-content: space-between; - flex: 1; - width: 100%; - cursor: pointer; - - .content { - margin-right: 60px; - } - } - - textarea.ant-input { - background-color: transparent; - box-shadow: none; - } - - .textarea-label { - position: relative; - top: 4px; - padding-left: 14px; - } - - .content { - flex: 1; - width: 100px; - height: 46px; - line-height: 30px; - padding: 8px 14px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - color: var(--ant-color-text-secondary); - - .title { - font-weight: var(--font-weight-normal); - padding-right: 10px; - color: var(--ant-color-text); - } - } -} diff --git a/src/components/seal-form/styles/slider.less b/src/components/seal-form/styles/slider.less deleted file mode 100644 index d819397c..00000000 --- a/src/components/seal-form/styles/slider.less +++ /dev/null @@ -1,24 +0,0 @@ -:local(.slider-label) { - display: flex; - justify-content: space-between; - align-items: flex-start; - width: 100%; - - :global(.val) { - color: var(--ant-color-text); - } - - :global(.label-val) { - position: absolute !important; - top: -14px; - right: -14px; - width: 80px; - border-radius: var(--border-radius-base); - text-align: center; - border: 1px solid var(--ant-color-border) !important; - - :global(.ant-input-number-input) { - text-align: center !important; - } - } -} diff --git a/src/components/seal-form/switch-input.tsx b/src/components/seal-form/switch-input.tsx deleted file mode 100644 index 76b85652..00000000 --- a/src/components/seal-form/switch-input.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Switch, Tooltip } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; -import LabelInfo from '../seal-form/components/label-info'; - -const SwitchContainer = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - gap: 8px; - border: 1px solid var(--ant-color-border); - border-radius: var(--ant-border-radius); - padding: 12px 14px; - min-height: 54px; -`; - -const LabelContainer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -interface SwitchInputProps { - label?: React.ReactNode; - description?: string; - checked?: boolean; - defaultChecked?: boolean; - onChange?: (checked: boolean) => void; - children?: React.ReactNode; - style?: React.CSSProperties; - alwaysShowChildren?: boolean; - btnTips?: React.ReactNode; - size?: 'small' | 'default'; -} - -const SwitchInput: React.FC = (props) => { - const { - label, - description, - checked, - defaultChecked, - onChange, - children, - style, - alwaysShowChildren = true, - size, - btnTips - } = props; - const [internalChecked, setInternalChecked] = useState( - defaultChecked || false - ); - - const handleChange = (checked: boolean) => { - setInternalChecked(checked); - onChange?.(checked); - }; - - return ( - - - - - - - - {(alwaysShowChildren || internalChecked) && children} - - ); -}; - -export default SwitchInput; diff --git a/src/components/seal-form/types.ts b/src/components/seal-form/types.ts deleted file mode 100644 index be806e37..00000000 --- a/src/components/seal-form/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; - -export interface SealFormItemProps { - label?: React.ReactNode; - required?: boolean; - isInFormItems?: boolean; - description?: React.ReactNode; - extra?: React.ReactNode; - addAfter?: React.ReactNode; - allowNull?: boolean; - loading?: React.ReactNode; - labelExtra?: React.ReactNode; - trim?: boolean; - checkStatus?: 'success' | 'error' | 'warning' | ''; -} diff --git a/src/components/seal-form/wrapper/auto-complete-label.ts b/src/components/seal-form/wrapper/auto-complete-label.ts deleted file mode 100644 index 3a3d40ab..00000000 --- a/src/components/seal-form/wrapper/auto-complete-label.ts +++ /dev/null @@ -1,28 +0,0 @@ -import styled from 'styled-components'; -import { BGCOLOR, INPUT_INNER_PADDING } from '../config'; - -const AutoCompleteLabel = styled.span` - position: absolute; - left: ${INPUT_INNER_PADDING}px; - height: 20px; - line-height: 20px; - top: 26px; - pointer-events: none; - transition: all 0.2s; - background-color: var(--ant-color-bg-container); - z-index: 10; - &.disabled { - background-color: #f5f5f5; - } - &.isfoucs-has-value { - // display: none; - z-index: -1; - // top: 9px; - // font-size: 12px; - // color: var(--ant-color-text); - // background-color: ${BGCOLOR}; - // padding: 0 4px; - } -`; - -export default AutoCompleteLabel; diff --git a/src/components/seal-form/wrapper/index.tsx b/src/components/seal-form/wrapper/index.tsx deleted file mode 100644 index 309a8ba8..00000000 --- a/src/components/seal-form/wrapper/index.tsx +++ /dev/null @@ -1,257 +0,0 @@ -import { theme } from 'antd'; -import classNames from 'classnames'; -import React, { FC } from 'react'; -import styled from 'styled-components'; -import LabelInfo from '../components/label-info'; -import { INPUT_INNER_PADDING } from '../config'; - -interface WrapperProps { - children: React.ReactNode; - label?: React.ReactNode; - noWrapperStyle?: boolean; - isFocus?: boolean; - classList?: string; - status?: string; // error | success | warning - required?: boolean; - description?: React.ReactNode; - className?: string; - disabled?: boolean; - extra?: React.ReactNode; - addAfter?: React.ReactNode; - variant?: string; - hasPrefix?: boolean; - labelExtra?: React.ReactNode; - onClick?: () => void; -} - -// wrapper box -const WrapperBox = styled.div` - position: relative; - display: flex; - justify-content: flex-start; - align-items: center; - height: 54px; - border-width: var(--ant-line-width); - border-style: var(--ant-line-type); - border-color: var(--ant-color-border); - border-radius: var(--border-radius-lg); - background-color: var(--ant-color-bg-container); - &.borderless { - border: none; - box-shadow: none; - } - &.filled { - border: none; - box-shadow: none; - } - &.borderless:focus-within { - border: none; - box-shadow: none; - } - &:hover { - border-color: var(--ant-input-hover-border-color); - transition: all 0.2s ease; - } - &:focus-within:not(.no-focus, .borderless) { - border-color: var(--ant-input-active-border-color); - box-shadow: var(--ant-input-active-shadow); - outline: 0; - background-color: var(--ant-input-active-bg); - } - &.validate-status-error:not(.seal-select-wrapper) { - border-width: var(--ant-line-width); - border-style: var(--ant-line-type); - border-color: var(--ant-color-error); - - &:hover { - border-color: var(--ant-color-error-border-hover); - } - - &:focus-within { - border-color: var(--ant-color-error); - } - } - &.seal-input-wrapper-disabled { - background-color: var(--ant-color-bg-container-disabled); - cursor: not-allowed; - - &:hover { - border-color: var(--ant-color-border); - - .ant-input-search-button { - border-color: var(--ant-color-border) !important; - color: var(--ant-color-text-description) !important; - } - } - } -`; - -// wrapper -const InnerWrapper = styled.div.attrs<{ - $noWrapperStyle?: boolean; - $nolabel?: boolean; -}>((props) => ({ - className: classNames({ - __wrapper__: true, - 'no-wrapper-style': props.$noWrapperStyle, - 'no-label': props.$nolabel - }) -}))` - position: relative; - display: flex; - flex-direction: column; - align-items: flex-start; - flex: 1; - padding-block: 20px 0; - max-width: 100%; - &:hover { - .ant-input-number-handler-wrap { - width: 34px !important; - } - } - &.no-wrapper-style { - padding-block: 0; - } - &.no-label { - padding-block: 0; - } -`; - -// label -export const Label = styled.div.attrs<{ - $isFocus?: boolean; - $hasPrefix?: boolean; -}>((props) => ({ - className: classNames({ - 'isfoucs-has-value': props.$isFocus, - 'blur-no-value': !props.$isFocus, - 'has-prefix': props.$hasPrefix - }) -}))` - position: absolute; - left: ${INPUT_INNER_PADDING}px; - color: rgba(0, 0, 0, 45%); - font-size: var(--font-size-base); - line-height: 1; - pointer-events: all; - display: flex; - width: max-content; - z-index: 5; - - &.isfoucs-has-value { - top: 10px; - transition: all 0.2s var(--seal-transition-func); - } - - &.blur-no-value { - top: 20px; - transition: all 0.2s var(--seal-transition-func); - } - - &.has-prefix { - top: 10px !important; - } -`; - -// inner -const Inner = styled.div.attrs({ - className: '__inner__' -})` - width: 100%; - display: flex; -`; - -const Extra = styled.div` - position: absolute; - right: 12px; - top: 8px; - z-index: 10; -`; - -const AddAfter = styled.div` - position: relative; - border-radius: 0 var(--ant-border-radius) var(--ant-border-radius) 0; - color: var(--ant-color-text-tertiary); - font-size: var(--font-size-base); - padding-inline: calc(var(--ant-padding-sm) - 1px); - height: 100%; - display: flex; - align-items: center; - background-color: var(--ant-color-fill-secondary); -`; - -// for wrapper - -const Wrapper: FC = ({ - children, - label, - isFocus, - status, - className, - disabled, - classList, - description, - required, - extra, - variant, - addAfter, - hasPrefix, - noWrapperStyle, - labelExtra, - onClick -}) => { - const { token } = theme.useToken(); - const wrapperClass = classNames( - status ? `validate-status-${status}` : '', - className, - classList, - variant, - { - 'seal-input-wrapper-addafter': addAfter, - 'seal-input-wrapper-disabled': disabled - } - ); - const wrapperStyle: Record = { - '--ant-line-width': '1px', - '--ant-line-type': 'solid', - '--ant-color-border': token.colorBorder, - '--ant-color-bg-container': token.colorBgContainer, - '--ant-color-bg-container-disabled': token.colorBgContainerDisabled, - '--ant-color-error': token.colorError, - '--ant-input-hover-border-color': token.colorPrimaryHover, - '--ant-color-error-border-hover': token.colorErrorBorderHover, - '--ant-input-active-border-color': token.colorPrimary, - '--ant-input-active-shadow': `0 0 0 2px ${token.controlOutline}`, - '--ant-input-active-bg': token.colorBgContainer - }; - return ( - - - {label && ( - - )} - {extra && {extra}} - {children} - - {addAfter && {addAfter}} - - ); -}; - -export default Wrapper; diff --git a/src/components/seal-form/wrapper/input.ts b/src/components/seal-form/wrapper/input.ts deleted file mode 100644 index fd2a1505..00000000 --- a/src/components/seal-form/wrapper/input.ts +++ /dev/null @@ -1,187 +0,0 @@ -import styled from 'styled-components'; -import { - BGCOLOR, - BORDERRADIUS, - INPUTHEIGHT, - INPUT_INNER_PADDING, - WRAPHEIGHT -} from '../config'; - -const InputWrapper = styled.div` - .seal-input-number { - padding-right: 0; - .isfoucs-has-value { - top: 9px; - } - } - - // ============= input initial ============= - .ant-input-outlined.ant-input-status-error:not(.ant-input-disabled) { - border: none; - box-shadow: none; - } - - .ant-input-outlined.ant-input-status-error:not(.ant-input-disabled):focus, - .ant-input-outlined.ant-input-status-error:not( - .ant-input-disabled - ):focus-within { - border: none; - box-shadow: none; - } - - .ant-input-number-outlined.ant-input-number-status-error:not( - .ant-input-number-disabled - ) { - border: none; - box-shadow: none; - } - - .ant-input-number-outlined.ant-input-number-status-error:not( - .ant-input-number-disabled - ):focus, - .ant-input-number-outlined.ant-input-number-status-error:not( - .ant-input-disabled - ):focus-within { - border: none; - box-shadow: none; - } - // ============= input initial end ============= - - .seal-input-wrapper-disabled { - background-color: var(--ant-color-bg-container-disabled); - cursor: not-allowed; - - &:hover { - border-color: var(--ant-color-border); - .ant-input-search-button { - border-color: var(--ant-color-border) !important; - color: var(--ant-color-text-description) !important; - } - } - } - .ant-input-number-input-wrap { - flex: 1; - } - .ant-input, - .ant-input-password { - flex: 1; - display: flex; - align-items: center; - border: none; - box-shadow: none; - padding-block: 5px; - padding-inline: ${INPUT_INNER_PADDING}px; - background-color: ${BGCOLOR}; - } - .ant-input.seal-textarea { - flex: 1; - overflow-y: auto !important; - } - - .ant-input-number { - flex: 1; - position: static; - display: flex; - align-items: center; - border: none; - box-shadow: none; - padding: 0; - background-color: ${BGCOLOR}; - flex: 1; - - &:hover .ant-input-number-handler-wrap, - &-focused .ant-input-number-handler-wrap { - width: 34px !important; - } - - &:hover { - cursor: text; - } - &.ant-input-number-disabled { - &:hover { - background-color: inherit; - } - } - } - .ant-input-outlined { - display: flex; - align-items: center; - border: none; - box-shadow: none; - padding-block: 5px; - padding-inline: ${INPUT_INNER_PADDING}px; - background-color: transparent; - } - .ant-input.ant-input-disabled { - background-color: transparent; - } - input.ant-input-number-input { - flex: 1; - padding-block: 6px 4px; - padding-inline: ${INPUT_INNER_PADDING}px; - } - .ant-input-group { - position: static; - } - .ant-input-group-addon { - inset-inline-start: unset !important; - border-radius: 0 ${BORDERRADIUS}px ${BORDERRADIUS}px 0; - width: 30px; - background-color: transparent; - border: none; - &:hover { - background-color: transparent !important; - } - } - .ant-input-group-wrapper-disabled { - .ant-input-group-addon { - background-color: transparent; - } - .ant-input-group-addon:hover { - background-color: transparent !important; - } - } - - &:not(.textarea-input-wrapper) { - .ant-input, - .ant-input-password, - .ant-input-number, - .ant-input-outlined, - input.ant-input-number-input { - height: ${INPUTHEIGHT}px !important; - } - } - .ant-input-search-button { - position: absolute; - top: -20px; - right: 1px; - border-radius: 0 ${BORDERRADIUS}px ${BORDERRADIUS}px 0 !important; - overflow: hidden; - border: none; - height: 52px; - border-left: var(--ant-line-width) var(--ant-line-type) - var(--ant-color-border); - } - .ant-input-number-handler-wrap { - top: 0; - height: ${WRAPHEIGHT - 2}px; - } - .ant-input-number-actions { - border-radius: 0 ${BORDERRADIUS}px ${BORDERRADIUS}px 0; - } - .seal-textarea-wrapper { - height: auto; - padding-right: 4px; - textarea { - overflow-y: auto !important; - } - } - .ant-input-textarea-allow-clear.ant-input-affix-wrapper { - padding: 0; - } - .ant-input-number-input:placeholder-shown { - font-size: var(--ant-font-size); - } -`; - -export default InputWrapper; diff --git a/src/components/seal-form/wrapper/select.ts b/src/components/seal-form/wrapper/select.ts deleted file mode 100644 index 928aa993..00000000 --- a/src/components/seal-form/wrapper/select.ts +++ /dev/null @@ -1,213 +0,0 @@ -import styled from 'styled-components'; -import { BORDERRADIUS, INPUT_INNER_PADDING, INPUTHEIGHT } from '../config'; - -const SelectWrapper = styled.div` - flex: 1; - .seal-select-wrapper { - border: none; - box-shadow: none; - - &.dropdown-visible { - .__wrapper__ { - .ant-cascader.ant-select.ant-select-outlined { - border-color: var(--ant-input-active-border-color) !important; - outline: 0; - background-color: var(--ant-input-active-bg); - border-bottom-color: transparent !important; - border-radius: ${BORDERRADIUS}px ${BORDERRADIUS}px 0 0; - transition: all 0.2s ease; - box-shadow: none; - - &::before { - content: ''; - position: absolute; - height: 1px; - margin-inline: 1px; - bottom: 0; - left: 0px; - right: 0; - background-color: var(--ant-color-split); - } - } - - .ant-select-dropdown { - box-shadow: none; - border-width: var(--ant-line-width); - border-style: var(--ant-line-type); - border-color: var(--ant-input-active-border-color); - border-top: none; - } - - &:hover { - .ant-select-dropdown { - border-color: var(--ant-input-active-border-color); - } - } - - &:focus-within { - border-color: var(--ant-input-active-border-color) !important; - outline: 0; - background-color: var(--ant-input-active-bg); - } - } - } - - &:focus-within { - border: none; - box-shadow: none; - } - .__wrapper__ { - padding-block: 0; - - .label { - left: ${INPUT_INNER_PADDING + 1}px !important; - top: 11px; - - &.isfoucs-has-value { - top: 11px; - transition: all 0.2s var(--seal-transition-func); - } - - &.blur-no-value { - top: 21px; - transition: all 0.2s var(--seal-transition-func); - } - - &.has-prefix { - top: 11px !important; - } - } - &.no-label { - padding-block: 0; - - .ant-select-arrow { - top: 50%; - } - - .ant-select .ant-select-input { - top: -5px !important; - } - .ant-select-placeholder { - position: absolute; - top: 1px; - left: 0; - right: 0; - } - .ant-select .ant-select-content { - padding-block: 0px 0; - } - .ant-select-auto-complete { - .ant-select-placeholder { - top: 1px; - } - } - .ant-select.ant-cascader { - .ant-select-placeholder { - top: 0px !important; - } - .ant-select-input { - top: -6px !important; - } - } - } - } - .ant-select-selection-overflow-item > span { - display: flex; - align-items: center; - } - .ant-select { - display: flex; - align-items: center; - height: 54px; - padding-inline: 14px !important; - - .ant-select-selection-wrap { - height: 100%; - } - - &.ant-select-auto-complete { - .ant-select-selection-search { - padding-inline-start: ${INPUT_INNER_PADDING}px; - } - .ant-select-content-value { - display: none; - } - } - &.ant-select-multiple.ant-cascader .ant-select-selection-search { - top: 0 !important; - } - - .ant-select-content { - padding-block: 20px 0; - box-shadow: none !important; - } - &.ant-cascader { - .ant-select-content-item-prefix + .ant-select-content-item-suffix { - margin-inline-start: 0 !important; - } - } - &.seal-cascader-small { - height: 40px; - } - - .ant-select-input { - top: 14px !important; - } - .ant-select-placeholder { - > span { - padding-inline: 0 !important; - } - } - } - - .ant-select-multiple.ant-select-lg { - .ant-select-selection-search { - margin-inline-start: 0 !important; - left: 0 !important; - } - } - - .ant-select-selection-item { - height: ${INPUTHEIGHT}px !important; - padding-block: 5px !important; - line-height: 22px !important; - padding-inline-end: 0 !important; - } - - .ant-select-arrow { - top: 32px; - } - - .ant-select-selection-search-input { - height: ${INPUTHEIGHT}px !important; - } - - &.validate-status-error { - .ant-select-dropdown { - border-color: var(--ant-color-error) !important; - } - .__wrapper__ { - .ant-cascader.ant-select.ant-select-outlined { - border-color: var(--ant-color-error) !important; - } - } - } - &.seal-cascader-wrapper-small { - height: 40px; - .cascader-popup-wrapper { - top: 39px !important; - } - .ant-select-input { - height: 36px !important; - } - .ant-select { - padding-inline: 12px !important; - } - .__wrapper__.no-label .ant-select.ant-cascader .ant-select-placeholder { - top: 50% !important; - } - } - } -`; - -export default SelectWrapper; diff --git a/src/components/seal-form/wrapper/slider.ts b/src/components/seal-form/wrapper/slider.ts deleted file mode 100644 index 6d97ff63..00000000 --- a/src/components/seal-form/wrapper/slider.ts +++ /dev/null @@ -1,57 +0,0 @@ -import styled from 'styled-components'; -import { INPUTHEIGHT, INPUT_INNER_PADDING } from '../config'; - -const SliderWrapper = styled.div` - .__wrapper__ { - height: 100%; - justify-content: center; - } - .label-wrapper { - width: 100%; - } - - .borderless { - background-color: transparent; - } - .ant-slider { - flex: 1; - } - padding-block: 0; - padding-inline: 2px; - input.ant-input-number-input { - text-align: center !important; - flex: 1; - height: ${INPUTHEIGHT}px !important; - padding-block: 5px; - padding-inline: ${INPUT_INNER_PADDING}px; - } - .isfoucs-has-value { - left: 0; - } - .slider-label { - display: flex; - justify-content: space-between; - align-items: flex-start; - width: 100%; - - .val { - color: var(--ant-color-text); - } - - .label-val { - position: absolute !important; - top: -14px; - right: 0px; - width: 80px; - border-radius: var(--border-radius-base); - text-align: center; - border: 1px solid var(--ant-color-border) !important; - - .ant-input-number-input { - text-align: center !important; - } - } - } -`; - -export default SliderWrapper; diff --git a/src/components/seal-table/components/cell-content.tsx b/src/components/seal-table/components/cell-content.tsx deleted file mode 100644 index 7b127341..00000000 --- a/src/components/seal-table/components/cell-content.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { CheckOutlined, FormOutlined, UndoOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Input, InputNumber, Tooltip } from 'antd'; -import _ from 'lodash'; -import React, { useContext, useEffect } from 'react'; -import styled from 'styled-components'; -import RowContext from '../row-context'; -import { CellContentProps } from '../types'; - -const CellContentWrapper = styled.div` - max-width: 100%; - display: flex; - align-items: center; -`; - -interface EditButtonsProps { - isEditing: boolean; - editable?: any; - handleSubmit: () => void; - handleUndo: () => void; - handleEdit: () => void; -} - -interface ContentProps { - isEditing: boolean; - current: any; - editable: any; - onChange: (val: any) => void; - row?: any; - render?: (text: any, record: any) => React.ReactNode; -} - -const EditButtons: React.FC = (props) => { - const intl = useIntl(); - const { isEditing, editable, handleSubmit, handleUndo, handleEdit } = props; - if (!editable) { - return null; - } - - if (isEditing) { - return ( - - - - - - - - - ); - } - return ( - - {editable.title || ''} - ) - } - > - - - - ); -}; - -const Content: React.FC = (props) => { - const { editable, current, isEditing, row, render, onChange } = props; - if (isEditing && editable) { - const isNumType = - typeof editable === 'object' && editable?.valueType === 'number'; - return isNumType ? ( - - ) : ( - onChange(e.target.value)} /> - ); - } - - if (render) { - return render(current, row); - } - return current; -}; - -const CellContent: React.FC = (props) => { - const { row, onCell } = useContext(RowContext); - const { dataIndex, render, editable } = props; - const [isEditing, setIsEditing] = React.useState(false); - const [current, setCurrent] = React.useState(row[dataIndex]); - const cachedValue = React.useRef(null); - - const handleEdit = () => { - setIsEditing(true); - }; - - const handleSubmit = async () => { - cachedValue.current = current; - await onCell?.( - { - ...row, - [dataIndex]: current - }, - { - dataIndex, - newValue: current, - oldValue: row[dataIndex] - } - ); - setIsEditing(false); - }; - - const handleUndo = () => { - setCurrent(cachedValue.current); - setIsEditing(false); - }; - - const handleValueChange = (val: any) => { - setCurrent(val); - }; - - useEffect(() => { - cachedValue.current = row[dataIndex]; - setCurrent(row[dataIndex]); - }, [row[dataIndex]]); - - return ( - - - - - ); -}; - -export default CellContent; diff --git a/src/components/seal-table/components/header-prefix.tsx b/src/components/seal-table/components/header-prefix.tsx deleted file mode 100644 index e324e5fe..00000000 --- a/src/components/seal-table/components/header-prefix.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import IconFont from '@/components/icon-font'; -import { useIntl } from '@umijs/max'; -import { Button, Checkbox } from 'antd'; -import _ from 'lodash'; -import React from 'react'; - -interface HeaderPrefixProps { - expandable?: boolean | React.ReactNode; - enableSelection?: boolean; - onSelectAll?: (e: any) => void; - onExpandAll?: (e: any) => void; - expandAll?: boolean; - indeterminate?: boolean; - selectAll?: boolean; - hasColumns?: boolean; - disabled?: boolean; -} - -const HeaderPrefix: React.FC = (props) => { - const { - hasColumns, - expandable, - enableSelection, - onSelectAll, - onExpandAll, - indeterminate, - selectAll, - expandAll, - disabled - } = props; - - const intl = useIntl(); - - const handleToggleExpand = () => { - onExpandAll?.(!expandAll); - }; - - const handleUnCheckAll = () => { - onSelectAll?.({ - target: { - checked: false - } - }); - }; - - if (!hasColumns) { - return null; - } - if (expandable && enableSelection) { - return ( -
    - - {_.isBoolean(expandable) ? ( - - ) : ( - expandable - )} - - -
    - ); - } - if (expandable) { - return ( -
    - - {_.isBoolean(expandable) ? ( - - ) : ( - expandable - )} - -
    - ); - } - if (enableSelection) { - return ( -
    - {} -
    - ); - } - return null; -}; - -export default HeaderPrefix; diff --git a/src/components/seal-table/components/header.tsx b/src/components/seal-table/components/header.tsx deleted file mode 100644 index 75cad7f7..00000000 --- a/src/components/seal-table/components/header.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Col, Row } from 'antd'; -import React from 'react'; -import { OnSortFn, SealColumnProps, TableOrder } from '../types'; -import TableHeader from './table-header'; - -interface HeaderProps { - columns: SealColumnProps[]; - sortDirections?: ('ascend' | 'descend' | null)[]; - sorterList: TableOrder | Array; - showSorterTooltip?: boolean; - onSort?: OnSortFn; -} - -const Header: React.FC = (props) => { - const { onSort, sortDirections, sorterList, showSorterTooltip } = props; - - return ( - - {props.columns?.map((columnProps, i) => { - const { - title, - dataIndex, - align, - width, - span, - headerStyle, - sortOrder, - sorter, - defaultSortOrder - } = columnProps as SealColumnProps; - return ( - - - - ); - })} - - ); -}; - -export default Header; diff --git a/src/components/seal-table/components/layout.tsx b/src/components/seal-table/components/layout.tsx deleted file mode 100644 index cc1a0e41..00000000 --- a/src/components/seal-table/components/layout.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import styled from 'styled-components'; - -const Row = styled.div.attrs<{ className?: string }>((props) => ({ - className: props.className -}))` - width: 100%; - display: flex; - justify-content: flex-start; - align-items: center; -`; - -const Col = styled.div<{ - $width?: string | number; - $align?: string; - $flexBasis?: string | number; - $maxWidth?: string | number; -}>` - flex: ${(props) => (props.$width ? 'none' : 1)}; - display: flex; - justify-content: ${(props) => props.$align || 'flex-start'}; - align-items: center; - width: ${({ $width }) => - $width ? (typeof $width === 'number' ? `${$width}px` : $width) : '10px'}; - ${({ $flexBasis }) => ($flexBasis ? `flex-basis: ${$flexBasis};` : '')} - ${({ $maxWidth }) => ($maxWidth ? `max-width: ${$maxWidth};` : '')} -`; - -export { Col, Row }; diff --git a/src/components/seal-table/components/pagination.tsx b/src/components/seal-table/components/pagination.tsx deleted file mode 100644 index 271fa0e3..00000000 --- a/src/components/seal-table/components/pagination.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { Pagination, type PaginationProps } from 'antd'; - -const PaginationComponent: React.FC = (props) => { - return ; -}; - -export default PaginationComponent; diff --git a/src/components/seal-table/components/row-children.tsx b/src/components/seal-table/components/row-children.tsx deleted file mode 100644 index e02899ea..00000000 --- a/src/components/seal-table/components/row-children.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import '../styles/row-children.less'; - -const RowChildren = (props: any) => { - const { children } = props; - - return
    {children}
    ; -}; - -export default RowChildren; diff --git a/src/components/seal-table/components/row-prefix.tsx b/src/components/seal-table/components/row-prefix.tsx deleted file mode 100644 index 9451c9c0..00000000 --- a/src/components/seal-table/components/row-prefix.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import IconFont from '@/components/icon-font'; -import { Button, Checkbox } from 'antd'; -import classNames from 'classnames'; -import _ from 'lodash'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -const ButtonWrapper = styled.div` - width: 30px; - margin-right: 5px; - &.disable-expand { - .ant-btn { - display: none; - } - } -`; - -interface RowPrefixProps { - expandable?: boolean | React.ReactNode; - enableSelection?: boolean; - expanded?: boolean; - checked?: boolean; - disableExpand?: boolean; - handleRowExpand?: () => void; - handleSelectChange?: (e: any) => void; -} - -const RowPrefix: React.FC = (props) => { - const { - expandable, - enableSelection, - expanded, - checked, - disableExpand, - handleRowExpand, - handleSelectChange - } = props; - - const isExpanded = useMemo(() => { - return expanded; - }, [expanded]); - - if (expandable && enableSelection) { - return ( -
    - - {_.isBoolean(expandable) ? ( - - ) : ( - expandable - )} - - -
    - ); - } - if (expandable) { - return ( -
    - - {_.isBoolean(expandable) ? ( - - ) : ( - expandable - )} - -
    - ); - } - if (enableSelection) { - return ( -
    - {} -
    - ); - } - return null; -}; - -export default RowPrefix; diff --git a/src/components/seal-table/components/table-body.tsx b/src/components/seal-table/components/table-body.tsx deleted file mode 100644 index 7e3f67b4..00000000 --- a/src/components/seal-table/components/table-body.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Empty } from 'antd'; -import React from 'react'; -import { SealColumnProps } from '../types'; -import TableRow from './table-row'; - -interface TableBodyProps { - dataSource: any[]; - columns: SealColumnProps[]; - rowKey: string; - rowSelection?: any; - expandable?: any; - expandedRowKeys?: any; - onExpand?: any; - childParentKey?: any; - pollingChildren?: any; - watchChildren?: any; - renderChildren?: any; - loadChildren?: any; - loadChildrenAPI?: any; - onCell?: any; - empty?: React.ReactNode; -} - -const TableBody: React.FC = ({ - dataSource, - rowKey, - rowSelection, - expandable, - expandedRowKeys, - onExpand, - childParentKey, - pollingChildren, - watchChildren, - renderChildren, - loadChildren, - loadChildrenAPI, - columns, - onCell, - empty -}) => { - if (!dataSource.length) { - return ( -
    - {empty || } -
    - ); - } - - return ( -
    - {dataSource.map((item, index) => ( - - ))} -
    - ); -}; - -export default TableBody; diff --git a/src/components/seal-table/components/table-cell.tsx b/src/components/seal-table/components/table-cell.tsx deleted file mode 100644 index a52d50bb..00000000 --- a/src/components/seal-table/components/table-cell.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import classNames from 'classnames'; -import React from 'react'; -import styled from 'styled-components'; -import { SealColumnProps } from '../types'; -import CellContent from './cell-content'; - -const CellWrapper = styled.div` - padding: var(--ant-table-cell-padding-block) - var(--ant-table-cell-padding-inline); - display: flex; - align-items: center; - justify-content: flex-start; - min-height: 68px; - word-break: break-word; - min-width: 20px; - overflow: hidden; - color: var(--ant-color-text-secondary); - - &.left { - justify-content: flex-start; - } - - &.right { - justify-content: flex-end; - } - - &.center { - justify-content: center; - } -`; - -const TableCell: React.FC = (props) => { - const { dataIndex, render, align, editable, dataField } = props; - - return ( - - - - ); -}; - -export default TableCell; diff --git a/src/components/seal-table/components/table-header.tsx b/src/components/seal-table/components/table-header.tsx deleted file mode 100644 index e9a6f9de..00000000 --- a/src/components/seal-table/components/table-header.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import classNames from 'classnames'; -import React, { useEffect } from 'react'; -import '../styles/header.less'; - -import { TableHeaderProps } from '../types'; - -const TableHeader: React.FC = (props) => { - const { - title, - style, - align, - firstCell, - lastCell, - sortOrder, - sortDirections = ['ascend', 'descend', null], - defaultSortOrder, - onSort, - sorterList, - sorter = false, - width, - dataIndex - } = props; - const intl = useIntl(); - - const [currentSortOrder, setCurrentSortOrder] = React.useState< - 'ascend' | 'descend' | null - >(sortOrder || defaultSortOrder || null); - - const getNextSortOrder = (currentOrder: 'ascend' | 'descend' | null) => { - const index = sortDirections.indexOf(currentOrder); - const nextIndex = (index + 1) % sortDirections.length; - return sortDirections[nextIndex]; - }; - - const nextSortTips = () => { - if (!currentSortOrder) { - return intl.formatMessage({ id: 'common.sorter.tips.ascend' }); - } - if (currentSortOrder === 'ascend') { - return intl.formatMessage({ id: 'common.sorter.tips.descend' }); - } - return intl.formatMessage({ id: 'common.sorter.tips.cancel' }); - }; - - const handleOnSort = () => { - setCurrentSortOrder((prev) => { - const next = getNextSortOrder(prev); - onSort?.( - { - columnKey: dataIndex, - field: dataIndex, - order: next - }, - sorter - ); - return next; - }); - }; - - useEffect(() => { - if (!sorterList) { - setCurrentSortOrder(null); - return; - } - - if (Array.isArray(sorterList)) { - const sortItem = sorterList.find( - (item) => item.columnKey === dataIndex || item.field === dataIndex - ); - setCurrentSortOrder(sortItem?.order || null); - } else { - if ( - sorterList.columnKey === dataIndex || - sorterList.field === dataIndex - ) { - setCurrentSortOrder(sorterList.order); - } else { - setCurrentSortOrder(null); - } - } - }, [sorterList]); - - return ( -
    - {sorter ? ( - - - {title} - - - - - - - ) : ( - - {title} - - )} -
    - ); -}; - -export default TableHeader; diff --git a/src/components/seal-table/components/table-row.tsx b/src/components/seal-table/components/table-row.tsx deleted file mode 100644 index a2ed177b..00000000 --- a/src/components/seal-table/components/table-row.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { createAxiosToken } from '@/hooks/use-chunk-request'; -import { useMemoizedFn } from 'ahooks'; -import { Col, Row, Spin } from 'antd'; -import classNames from 'classnames'; -import _ from 'lodash'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import RowContext from '../row-context'; -import TableContext from '../table-context'; -import { RowContextProps, SealTableProps } from '../types'; -import RowPrefix from './row-prefix'; -import TableCell from './table-cell'; - -const TableRow: React.FC< - RowContextProps & - Omit -> = (props) => { - const { - record, - rowIndex, - expandable, - rowSelection, - expandedRowKeys = [], - rowKey, - childParentKey, - columns, - pollingChildren, - watchChildren, - onCell, - onExpand, - renderChildren, - loadChildren, - loadChildrenAPI - } = props; - const tableContext: any = React.useContext<{ - allChildren?: any[]; - setDisableExpand?: (record: any) => boolean; - }>(TableContext); - const [childrenData, setChildrenData] = useState([]); - const [loading, setLoading] = useState(false); - const pollTimer = useRef(null); - const chunkRequestRef = useRef(null); - const childrenDataRef = useRef([]); - childrenDataRef.current = childrenData; - const axiosToken = useRef(null); - const [updateChild, setUpdateChild] = useState(true); - const [currentExpand, setCurrentExpand] = useState(false); - - useEffect(() => { - return () => { - if (pollTimer.current) { - clearInterval(pollTimer.current); - } - chunkRequestRef.current?.current?.cancel?.(); - axiosToken.current?.cancel?.(); - }; - }, []); - - const expanded = useMemo(() => { - return expandedRowKeys?.includes(record[rowKey]); - }, [expandedRowKeys]); - - const checked = useMemo(() => { - return rowSelection?.selectedRowKeys?.includes(record[rowKey]); - }, [rowSelection?.selectedRowKeys, record, rowKey]); - - useEffect(() => { - if (expandedRowKeys?.length === 0) { - setCurrentExpand(false); - } - }, [expandedRowKeys.length]); - - const renderChildrenData = () => { - if (childrenData.length === 0) { - return null; - } - return renderChildren?.(childrenData, { - parent: record, - currentExpanded: currentExpand - }); - }; - - const handlePolling = async () => { - if (pollingChildren) { - try { - const data = await loadChildren?.(record); - setChildrenData(data || []); - } catch (error) { - setChildrenData([]); - } - } - }; - - const handleLoadChildren = useMemoizedFn(async () => { - try { - axiosToken.current?.cancel?.(); - axiosToken.current = createAxiosToken(); - setLoading(true); - const data = await loadChildren?.(record, { - token: axiosToken.current?.token - }); - - setChildrenData(data || []); - setLoading(false); - } catch (error) { - setChildrenData([]); - setLoading(false); - } - }); - - const filterUpdateChildrenHandler = () => { - const dataList = _.filter(tableContext.allChildren, (data: any) => { - return _.get(data, [childParentKey]) === _.get(record, [rowKey]); - }); - setChildrenData(dataList); - }; - - const handleRowExpand = async () => { - onExpand?.(!expanded, record, record[rowKey]); - setCurrentExpand(!expanded); - - if (pollTimer.current) { - clearInterval(pollTimer.current); - } - - if (expanded) { - axiosToken.current?.cancel?.(); - return; - } - - if (pollingChildren) { - await handleLoadChildren(); - pollTimer.current = setInterval(() => { - handlePolling(); - }, 1000); - } else { - handleLoadChildren(); - } - }; - - const handleSelectChange = (e: any) => { - if (e.target.checked) { - // update selectedRowKeys - rowSelection?.onChange( - _.uniq([...rowSelection?.selectedRowKeys, record[rowKey]]), - _.uniqBy([...rowSelection?.selectedRows, record], rowKey) - ); - } else { - // update selectedRowKeys - rowSelection?.onChange( - rowSelection?.selectedRowKeys.filter((key) => key !== record[rowKey]), - rowSelection?.selectedRows.filter( - (row) => row[rowKey] !== record[rowKey] - ) - ); - } - }; - - const disableExpand = useMemo(() => { - return tableContext.setDisableExpand?.(record); - }, [tableContext.setDisableExpand, record]); - - useEffect(() => { - const handleVisibilityChange = async () => { - if (document.visibilityState === 'hidden') { - setUpdateChild(false); - } else { - setUpdateChild(true); - } - }; - - document.addEventListener('visibilitychange', handleVisibilityChange); - - return () => { - document.removeEventListener('visibilitychange', handleVisibilityChange); - }; - }, []); - - useEffect(() => { - if (updateChild) { - // for update watch data - filterUpdateChildrenHandler(); - } - return () => { - chunkRequestRef.current?.current?.cancel?.(); - }; - }, [updateChild, tableContext.allChildren]); - - return ( - -
    -
    - - - {columns?.map(({ key, ...restProps }) => { - return ( - - - - ); - })} - -
    - {expanded && !disableExpand && ( -
    - - {renderChildrenData()} - -
    - )} -
    -
    - ); -}; - -export default TableRow; diff --git a/src/components/seal-table/components/table-skeleton.tsx b/src/components/seal-table/components/table-skeleton.tsx deleted file mode 100644 index ef270179..00000000 --- a/src/components/seal-table/components/table-skeleton.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Checkbox } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; -import '../styles/skeleton.less'; - -const SkeletonItem = () => { - return ( -
    -
    - -
    - ); -}; - -const Wrapper = styled.div` - display: flex; - flex-direction: column; - gap: 20px; -`; - -const TableSkeleton = () => { - const dataSource = Array.from({ length: 5 }); - return ( - - {dataSource.map((item, index) => ( - - ))} - - ); -}; - -export default React.memo(TableSkeleton); diff --git a/src/components/seal-table/index.tsx b/src/components/seal-table/index.tsx deleted file mode 100644 index 58d37204..00000000 --- a/src/components/seal-table/index.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { Pagination, Spin, theme, type PaginationProps } from 'antd'; -import _ from 'lodash'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; -import Header from './components/header'; -import HeaderPrefix from './components/header-prefix'; -import TableBody from './components/table-body'; -import './styles/index.less'; -import { SealColumnProps, SealTableProps } from './types'; -import useSorter from './use-sorter'; - -const Wrapper = styled.div<{ $token: any }>` - width: 100%; - --ant-table-cell-padding-inline: ${(props) => - props.$token.cellPaddingInline}px; - --ant-table-cell-padding-block: ${(props) => props.$token.cellPaddingBlock}px; - --ant-table-header-border-radius: ${(props) => - props.$token.headerBorderRadius}px; - --ant-table-header-split-color: ${(props) => - props.$token.colorBorderSecondary}; - --ant-table-row-selected-bg: ${(props) => props.$token.rowSelectedBg}; - --ant-table-row-selected-hover-bg: ${(props) => - props.$token.rowSelectedHoverBg}; - --ant-table-row-hover-bg: ${(props) => props.$token.rowHoverBg}; - --ant-table-header-icon-color: ${(props) => - props.$token.tableHeaderIconColor}; - --ant-table-header-icon-hover-color: ${(props) => - props.$token.tableHeaderIconHoverColor}; -`; - -const SealTable: React.FC = ( - props -) => { - const { - columns, - children, - rowKey, - childParentKey, - onExpand, - onExpandAll, - onTableSort, - onCell, - expandedRowKeys, - loading, - loadend, - expandable, - pollingChildren, - watchChildren, - rowSelection, - pagination, - empty, - sortDirections, - showSorterTooltip, - renderChildren, - loadChildren, - loadChildrenAPI - } = props; - const { handleOnTableSort, sorterList } = useSorter({ - onTableSort, - columns - }); - const { token } = theme.useToken(); - const parsedColumns = useMemo(() => { - if (columns) return columns; - - return React.Children.toArray(children) - .filter(React.isValidElement) - .map((child) => { - const column = child as React.ReactElement; - const { title, dataIndex, key, render, ...restProps } = column.props; - - return { - title, - dataIndex, - key: key || dataIndex, - render, - ...restProps - }; - }); - }, [columns, children]); - - const expandAll = useMemo(() => { - if (expandedRowKeys?.length === 0) { - return false; - } - const allKeys = new Set(expandedRowKeys); - const currentDataKeys = props.dataSource.map((record) => record[rowKey]); - return currentDataKeys.every((key) => allKeys.has(key)); - }, [props.dataSource, expandedRowKeys]); - - const selectState = useMemo(() => { - const selectedRowKeys = rowSelection?.selectedRowKeys || []; - const selectedKeys = new Set(selectedRowKeys); - const allRowKeys = props.dataSource.map((record) => record[rowKey]); - if (!selectedRowKeys?.length) { - return { - selectAll: false, - indeterminate: false - }; - } - if (allRowKeys.every((key) => selectedKeys.has(key))) { - return { - selectAll: true, - indeterminate: false - }; - } - return { - selectAll: false, - indeterminate: true - }; - }, [rowSelection?.selectedRowKeys, props.dataSource, rowKey]); - - const selectAllRows = () => { - const allKeys = new Set([ - ...props.dataSource.map((record) => record[rowKey]), - ...(rowSelection?.selectedRowKeys || []) - ]); - const allDatas = _.uniqBy( - [...props.dataSource, ...(rowSelection?.selectedRows || [])], - (record: any) => record[rowKey] - ); - - rowSelection?.onChange([...allKeys], allDatas); - }; - - const deselectAllRows = () => { - const currentKeys = props.dataSource.map((record) => record[rowKey]); - rowSelection?.removeSelectedKeys?.(currentKeys); - }; - - const handleSelectAllChange = (e: any) => { - if (e.target.checked) { - selectAllRows(); - } else { - deselectAllRows(); - } - }; - - const handleExpandAll = (value: boolean) => { - onExpandAll?.(value); - }; - - const handlePageChange = (page: number, pageSize: number) => { - pagination?.onChange?.(page, pageSize); - }; - - const handlePageSizeChange = (current: number, size: number) => { - pagination?.onShowSizeChange?.(current, size); - }; - - console.log('token.table', token); - - return ( - -
    -
    - 0} - > -
    -
    - - - -
    - {pagination && ( -
    - -
    - )} -
    - ); -}; - -export default SealTable; diff --git a/src/components/seal-table/row-context.ts b/src/components/seal-table/row-context.ts deleted file mode 100644 index 86b0e1b6..00000000 --- a/src/components/seal-table/row-context.ts +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -interface RowContextType { - row: Record; - onCell?: ( - record: any, - data: { dataIndex: string; newValue: any; oldValue: any } - ) => any; -} - -const RowContext = React.createContext({} as RowContextType); - -export default RowContext; diff --git a/src/components/seal-table/styles/cell.less b/src/components/seal-table/styles/cell.less deleted file mode 100644 index f6a5260a..00000000 --- a/src/components/seal-table/styles/cell.less +++ /dev/null @@ -1,28 +0,0 @@ -.cell { - padding: var(--ant-table-cell-padding-block) - var(--ant-table-cell-padding-inline); - display: flex; - align-items: center; - justify-content: flex-start; - min-height: 68px; - word-break: break-word; - min-width: 20px; - overflow: hidden; - - .cell-content { - max-width: 100%; - line-height: 18px; - } - - &.left { - justify-content: flex-start; - } - - &.right { - justify-content: flex-end; - } - - &.center { - justify-content: center; - } -} diff --git a/src/components/seal-table/styles/header.less b/src/components/seal-table/styles/header.less deleted file mode 100644 index 9f40955a..00000000 --- a/src/components/seal-table/styles/header.less +++ /dev/null @@ -1,89 +0,0 @@ -.table-header { - position: relative; - min-height: 20px; - display: flex; - align-items: center; - justify-content: flex-start; - height: 50px; - padding-inline: var(--ant-table-cell-padding-inline); - color: var(--color-text-table-header); - - &::before { - position: absolute; - top: 50%; - inset-inline-end: 0; - width: 1px; - height: 1.6em; - background-color: var(--ant-table-header-split-color); - transform: translateY(-50%); - content: ''; - } - - &-last { - border-right: none; - } - - &-cell { - font-weight: 500; - } - - &-left { - justify-content: flex-start; - } - - &-right { - justify-content: flex-end; - } - - &-center { - justify-content: center; - } - - &:hover { - .sorter-header { - .sorter { - .anticon { - color: var(--ant-table-header-icon-hover-color); - } - } - } - } - - .sorter-header { - display: flex; - flex: 1; - width: 100%; - justify-content: space-between; - align-items: center; - cursor: pointer; - - .sorter { - display: flex; - flex-direction: column; - align-items: center; - margin-left: 4px; - - .anticon { - font-size: 12px; - color: var(--ant-table-header-icon-color); - transition: color var(--ant-motion-duration-slow); - } - - .sorter-up { - margin-bottom: -0.125em; - } - - .sorter-down { - margin-top: -0.125em; - } - - .sorter-active { - color: var(--ant-color-primary); - - .anticon { - color: var(--ant-color-primary); - } - } - } - } -} diff --git a/src/components/seal-table/styles/index.less b/src/components/seal-table/styles/index.less deleted file mode 100644 index 89d2ac23..00000000 --- a/src/components/seal-table/styles/index.less +++ /dev/null @@ -1,92 +0,0 @@ -.pagination-wrapper { - display: flex; - justify-content: flex-end; - margin: var(--ant-margin) 0; -} - -.seal-table-container { - display: flex; - flex-direction: column; - width: 100%; - - .header-row-wrapper { - height: 50px; - display: flex; - justify-content: flex-start; - align-items: center; - background-color: var(--ant-color-fill-tertiary); - border-radius: var(--ant-table-header-border-radius) - var(--ant-table-header-border-radius) 0 0; - - .header-row-prefix-wrapper { - padding-left: var(--ant-table-cell-padding-inline); - } - - .row { - flex: 1; - } - } - - .row-box { - overflow: hidden; - border-bottom: 1px solid var(--ant-color-split); - } - - .expanded-row { - padding: 16px; - border-top: 0; - border-radius: 0 0 var(--ant-table-header-border-radius) - var(--ant-table-header-border-radius); - - .ant-empty-image { - height: 30px; - } - } - - .row-wrapper { - display: flex; - justify-content: flex-start; - align-items: center; - transition: all 0.2s ease; - - &:hover { - background-color: var(--ant-table-row-hover-bg); - transition: all 0.2s ease; - } - - &-selected { - transition: all 0.2s ease; - - &:hover { - background-color: var(--ant-table-row-hover-bg); - transition: all 0.2s ease; - } - } - - .row-prefix-wrapper { - display: flex; - align-items: center; - padding-left: var(--ant-table-cell-padding-inline); - } - } - - .seal-table-row { - flex: 1; - } - - .spin { - text-align: center; - display: flex; - justify-content: center; - align-items: center; - margin-top: 20px; - min-height: 100px; - } - - .empty-wrapper { - display: flex; - min-height: 160px; - justify-content: center; - align-items: center; - } -} diff --git a/src/components/seal-table/styles/row-children.less b/src/components/seal-table/styles/row-children.less deleted file mode 100644 index 43fd8f86..00000000 --- a/src/components/seal-table/styles/row-children.less +++ /dev/null @@ -1,13 +0,0 @@ -.row-children { - position: relative; - display: flex; - align-items: center; - height: 54px; - border-radius: var(--border-radius-mdium); - transition: all 0.2s ease; - - &:hover { - background-color: var(--ant-table-row-hover-bg); - transition: all 0.2s ease; - } -} diff --git a/src/components/seal-table/styles/skeleton.less b/src/components/seal-table/styles/skeleton.less deleted file mode 100644 index 0c0cdea6..00000000 --- a/src/components/seal-table/styles/skeleton.less +++ /dev/null @@ -1,13 +0,0 @@ -.row-skeleton { - display: flex; - justify-content: flex-start; - background-color: var(--ant-color-fill-tertiary); - padding: 16px; - height: 68px; - border-radius: var(--border-radius-base); - align-items: center; - - .holder { - width: 33px; - } -} diff --git a/src/components/seal-table/table-context.ts b/src/components/seal-table/table-context.ts deleted file mode 100644 index 496f0b7a..00000000 --- a/src/components/seal-table/table-context.ts +++ /dev/null @@ -1,5 +0,0 @@ -import React from 'react'; - -const TableContext = React.createContext({}); - -export default TableContext; diff --git a/src/components/seal-table/types.ts b/src/components/seal-table/types.ts deleted file mode 100644 index 5edb9633..00000000 --- a/src/components/seal-table/types.ts +++ /dev/null @@ -1,114 +0,0 @@ -import React from 'react'; - -export type OnSortFn = ( - order: { - columnKey: string; - field: string; - order: 'ascend' | 'descend' | null; - }, - sorter: boolean | { multiple?: number } -) => void; - -export interface CellContentProps { - dataIndex: string; - render?: (text: any, record: any) => React.ReactNode; - editable?: - | boolean - | { - valueType?: 'text' | 'number' | 'date' | 'datetime' | 'time'; - title?: React.ReactNode; - }; -} - -export interface SealColumnProps { - title: React.ReactNode; - render?: (text: any, record: any) => React.ReactNode; - dataIndex: string; - key?: string; - dataField?: string; // Added dataField property, aviods conflict with dataIndex, because dataIndex maybe used in sorting - width?: number; - span: number; - align?: 'left' | 'center' | 'right'; - headerStyle?: React.CSSProperties; - sorter?: boolean | { multiple?: number }; - defaultSortOrder?: 'ascend' | 'descend'; - editable?: - | boolean - | { - valueType?: 'text' | 'number' | 'date' | 'datetime' | 'time'; - title?: React.ReactNode; - }; - valueType?: 'text' | 'number' | 'date' | 'datetime' | 'time'; - sortOrder?: 'ascend' | 'descend' | null; - [key: string]: any; -} - -export interface TableHeaderProps { - showSorterTooltip?: boolean; - sorterList?: TableOrder | Array; - sorter?: boolean | { multiple?: number }; - sortDirections?: ('ascend' | 'descend' | null)[]; - defaultSortOrder?: 'ascend' | 'descend' | null; - sortOrder?: 'ascend' | 'descend' | null; - dataIndex: string; - onSort?: OnSortFn; - title: React.ReactNode; - style?: React.CSSProperties; - firstCell?: boolean; - lastCell?: boolean; - align?: 'left' | 'center' | 'right'; - width?: number | string; - sortedDataIndexList?: Array<{ - columnKey: string; - field: string; - order: 'ascend' | 'descend' | null; - }>; -} - -export interface RowSelectionProps { - selectedRowKeys: React.Key[]; - selectedRows: any[]; - enableSelection: boolean; - removeSelectedKeys: (rowKeys: React.Key[]) => void; - onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => void; -} - -export type TableOrder = { - columnKey?: string; - field?: string; - order: 'ascend' | 'descend' | null; -}; -export interface SealTableProps { - showSorterTooltip?: boolean; - sortDirections?: ('ascend' | 'descend' | null)[]; - columns?: SealColumnProps[]; - childParentKey?: string; - expandedRowKeys?: React.Key[]; - rowSelection?: RowSelectionProps; - children?: React.ReactElement[]; - empty?: React.ReactNode; - expandable?: React.ReactNode; - dataSource: any[]; - pollingChildren?: boolean; - watchChildren?: boolean; - loading?: boolean; - loadend?: boolean; - onCell?: (record: any, extra: any) => void; - onTableSort?: (order: TableOrder | Array) => void; - onExpand?: (expanded: boolean, record: any, rowKey: any) => void; - onExpandAll?: (expanded: boolean) => void; - renderChildren?: ( - data: any, - options: { parent?: any; [key: string]: any } - ) => React.ReactNode; - loadChildren?: (record: any, options?: any) => Promise; - loadChildrenAPI?: (record: any) => string; - contentRendered?: () => void; - rowKey: string; -} - -export interface RowContextProps { - record: Record; - pollingChildren?: boolean; - rowIndex: number; -} diff --git a/src/components/seal-table/use-sorter.ts b/src/components/seal-table/use-sorter.ts deleted file mode 100644 index 12642313..00000000 --- a/src/components/seal-table/use-sorter.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { isBoolean } from 'lodash'; -import { useRef, useState } from 'react'; -import { SealColumnProps, TableOrder } from './types'; - -const initSorterList = (columns: SealColumnProps[]) => { - const list = columns.filter((col) => col.defaultSortOrder); - if (list.length === 0) { - return []; - } - - return list.map((col) => ({ - columnKey: col.key || col.dataIndex, - field: col.dataIndex, - order: col.defaultSortOrder || null - })); -}; - -export default function useSorter(options: { - onTableSort?: (TableOrder: TableOrder | Array) => void; - columns?: SealColumnProps[]; -}) { - const { onTableSort, columns } = options; - const sorterListRef = useRef>( - initSorterList(columns || []) - ); - const [sorterList, setSorterList] = useState>( - initSorterList(columns || []) - ); - - const handleOnTableSort = ( - order: TableOrder, - sorter: boolean | { multiple?: number } - ) => { - let currentOrder: TableOrder = { ...order }; - - if (order.order === null) { - currentOrder = { - columnKey: undefined, - field: undefined, - order: null - }; - } - // single column sort - if (isBoolean(sorter)) { - setSorterList(currentOrder); - sorterListRef.current = currentOrder; - - onTableSort?.(sorterListRef.current); - return; - } - - // multi column sort - if (sorter && typeof sorter === 'object' && sorter.multiple) { - if (!Array.isArray(sorterListRef.current)) { - if ( - sorterListRef.current.columnKey === currentOrder.columnKey || - sorterListRef.current.field === currentOrder.field - ) { - // remove the sorter if order is null - sorterListRef.current = { - ...currentOrder - }; - } else { - sorterListRef.current = [sorterListRef.current, { ...currentOrder }]; - } - } else if (Array.isArray(sorterListRef.current)) { - const existingIndex = sorterListRef.current.findIndex( - (item) => - item.columnKey === order.columnKey || item.field === order.field - ); - - if (existingIndex !== -1) { - sorterListRef.current.splice(existingIndex, 1); - sorterListRef.current.push({ ...currentOrder }); - } else { - sorterListRef.current.push({ ...currentOrder }); - } - } - } - setSorterList(sorterListRef.current); - - onTableSort?.(sorterListRef.current); - }; - - return { - sorterListRef, - sorterList, - handleOnTableSort - }; -} diff --git a/src/components/segment-line/index.tsx b/src/components/segment-line/index.tsx deleted file mode 100644 index d9f7cb9b..00000000 --- a/src/components/segment-line/index.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { Segmented, type SegmentedProps } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -interface ThemeType { - color: string; - itemColorHover: string; - itemSelectedColor: string; - thumbBgColor: string; - fontWeight: number; -} -interface SegmentLineProps extends SegmentedProps { - height?: number; - theme?: 'dark' | 'light'; - showTitle?: boolean; -} - -const darkTheme: ThemeType = { - color: 'var(--color-white-tertiary)', - itemColorHover: 'var(--color-white-secondary)', - itemSelectedColor: 'var(--color-white-primary)', - thumbBgColor: 'var(--color-white-primary)', - fontWeight: 400 -}; - -const lightTheme: ThemeType = { - color: 'var(--ant-segmented-item-color)', - itemColorHover: 'var(--ant-segmented-item-hover-color)', - itemSelectedColor: 'var(--ant-segmented-item-selected-color)', - thumbBgColor: 'var(--ant-color-primary)', - fontWeight: 500 -}; - -const SegmentedQwrapper = styled.div<{ - $height: number; - $theme: ThemeType; -}>` - .ant-segmented.segment-line { - padding: 0; - background-color: transparent; - color: ${(props) => props.$theme.color}; - font-weight: ${(props) => props.$theme.fontWeight}; - border: none; - box-shadow: none; - height: ${(props) => props.$height}px; - display: flex; - align-items: center; - .ant-segmented-group { - gap: 16px; - height: 100%; - } - .ant-segmented-item:hover { - color: ${(props) => props.$theme.itemColorHover}; - } - .ant-segmented-thumb { - height: 2px; - padding: 0px; - bottom: 0px; - top: unset; - background-color: ${(props) => props.$theme.thumbBgColor} !important; - } - .ant-segmented-item-label { - display: flex; - align-items: center; - padding: 0; - font-size: var(--font-size-small); - } - .ant-segmented-item { - background-color: transparent; - padding-bottom: 2px; - display: flex; - align-items: center; - &::after { - background-color: ${(props) => props.$theme.thumbBgColor} !important; - width: 100%; - height: 0px; - border-radius: 2px; - bottom: 0px; - top: unset; - opacity: 1; - } - } - - .ant-segmented-item-selected { - background-color: transparent; - box-shadow: none; - color: ${(props) => props.$theme.itemSelectedColor}; - &::after { - height: 2px; - opacity: 1; - } - } - } - &.with-title .ant-segmented.segment-line { - .ant-segmented-item.ant-segmented-item-selected::after { - display: none; - } - } -`; - -const SegmentLine: React.FC = (props) => { - const { - height = 32, - size = 'small', - options = [], - className = 'segment-line', - theme = 'dark', - showTitle = false, - ...rest - } = props; - - return ( - - - - ); -}; - -export default SegmentLine; diff --git a/src/components/short-cuts/index.less b/src/components/short-cuts/index.less deleted file mode 100644 index c409b0a2..00000000 --- a/src/components/short-cuts/index.less +++ /dev/null @@ -1,42 +0,0 @@ -.short-cuts { - margin-bottom: 10px; - - .ant-table-container .ant-table-content table tr > td { - height: auto; - border-bottom: var(--ant-line-width) var(--ant-line-type) - var(--ant-table-border-color); - } - - .ant-table-container .ant-table-content table { - border-spacing: 0; - - .ant-table-tbody .ant-table-row { - background: transparent; - } - - tr > td:first-child { - border-radius: 0; - } - - tr > td:last-child { - border-radius: 0; - } - - .ant-table-thead > tr > th { - background-color: var(--ant-color-fill-tertiary); - height: 36px; - padding-block: 0; - } - } - - .ant-table-fixed-header { - // .ant-table-body { - // overflow-y: auto !important; - // } - .ant-table-thead > tr > th { - background-color: var(--ant-color-fill-tertiary); - height: 36px; - padding-block: 0; - } - } -} diff --git a/src/components/short-cuts/index.tsx b/src/components/short-cuts/index.tsx deleted file mode 100644 index 0012bfb9..00000000 --- a/src/components/short-cuts/index.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { SearchOutlined } from '@ant-design/icons'; -import { Input, Table, Tag } from 'antd'; -import _ from 'lodash'; -import React from 'react'; -import './index.less'; -import KeyMapConfig from './keymap'; - -const ShortCuts: React.FC<{ intl: any }> = ({ intl }) => { - const [dataList, setDataList] = React.useState(KeyMapConfig); - - const columns = [ - { - title: 'Scope', - dataIndex: 'scope', - key: 'scope', - width: 160 - }, - { - title: 'Action', - dataIndex: 'command', - key: 'command', - render: (text: string, row: any) => { - return {intl.formatMessage({ id: text })}; - } - }, - { - title: 'Keybinding', - dataIndex: 'keybinding', - key: 'keybinding', - width: 180, - render: (text: string, row: any) => { - return {row.keybinding}; - } - } - ]; - - const handleInputChange = (e: any) => { - const value = e.target.value; - const list = _.filter(KeyMapConfig, (item: any) => { - return ( - item.command.toLowerCase().includes(value.toLowerCase()) || - item.scope.toLowerCase().includes(value.toLowerCase()) - ); - }); - setDataList(list); - }; - - const debounceHandleInputChange = _.debounce(handleInputChange, 300); - return ( -
    -

    - {intl.formatMessage({ id: 'shortcuts.title' })} -

    - - - - } - > - record.command} - columns={columns} - dataSource={dataList} - pagination={false} - scroll={{ y: 450 }} - >
    -
    - ); -}; - -export const modalConfig = { - icon: null, - centered: false, - mask: { - closeable: true - }, - footer: null, - style: { - top: '10%' - }, - width: 700 -}; - -export default ShortCuts; diff --git a/src/components/short-cuts/keymap.ts b/src/components/short-cuts/keymap.ts deleted file mode 100644 index 1415b980..00000000 --- a/src/components/short-cuts/keymap.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { KeyMap } from '@/config/hotkeys'; -export default [ - { - scope: 'playground', - command: 'shortcuts.playground.newmessage', - keybinding: KeyMap.CREATE.iconKeybinding - }, - { - scope: 'playground', - command: 'shortcuts.playground.clearmessage', - keybinding: KeyMap.CLEAR.iconKeybinding - }, - { - scope: 'playground', - command: 'shortcuts.playground.toggleparams', - keybinding: KeyMap.RIGHT.iconKeybinding - }, - { - scope: 'models', - // span: { - // rowSpan: 3, - // colSpan: 1 - // }, - command: 'shortcuts.models.newmodelHF', - keybinding: KeyMap.NEW1.iconKeybinding - }, - { - scope: 'models', - command: 'shortcuts.models.newmodelLM', - keybinding: KeyMap.NEW2.iconKeybinding - // span: { - // rowSpan: 0, - // colSpan: 0 - // } - }, - { - scope: 'models', - command: 'shortcuts.models.search', - keybinding: KeyMap.SEARCH.iconKeybinding - // span: { - // rowSpan: 0, - // colSpan: 0 - // } - }, - { - scope: 'resources', - command: 'shortcuts.resources.addworker', - keybinding: KeyMap.CREATE.iconKeybinding - }, - { - scope: 'API keys', - command: 'shortcuts.apikeys.new', - keybinding: KeyMap.CREATE.iconKeybinding - }, - { - scope: 'users', - command: 'shortcuts.users.new', - keybinding: KeyMap.CREATE.iconKeybinding - } -]; diff --git a/src/components/simple-overlay/index.tsx b/src/components/simple-overlay/index.tsx deleted file mode 100644 index 320ac2d1..00000000 --- a/src/components/simple-overlay/index.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import useUserSettings from '@/hooks/use-user-settings'; -import React, { useEffect } from 'react'; -import SimpleBar from 'simplebar-react'; -import 'simplebar-react/dist/simplebar.min.css'; -import styled from 'styled-components'; - -const Wrapper = styled.div` - .simplebar-scrollbar::before { - width: var(--scrollbar-size); - background: var(--scrollbar-handle-bg); - } - &.dark { - .simplebar-scrollbar::before { - width: var(--scrollbar-size); - background: var(--scrollbar-handle-light-bg); - } - } -`; - -interface SimpleOverlayProps { - height?: string | number; - children?: React.ReactNode; - style?: React.CSSProperties; - onScrollEnd?: (e: React.UIEvent) => void; - disableTrigger?: boolean; -} - -const SimpleOverlay: React.FC = ({ - height, - children, - style, - disableTrigger, - onScrollEnd -}) => { - const { isDarkTheme } = useUserSettings(); - const simpleBarRef = React.useRef(null); - - useEffect(() => { - // simpleBarRef.current.recalculate(); - - const onScroll = (e: React.UIEvent) => { - const scrollElement = simpleBarRef.current?.getScrollElement(); - const scrollHeight = scrollElement.scrollHeight; - const clientHeight = scrollElement.clientHeight; - const scrollTop = scrollElement.scrollTop; - - // Check if the scrollbar is at the bottom 20px for buffer - const isAtBottom = scrollHeight - clientHeight - scrollTop <= 20; - if (isAtBottom && !disableTrigger) { - onScrollEnd?.(e); - } - }; - simpleBarRef.current - ?.getScrollElement() - .addEventListener('scroll', onScroll); - - return () => { - simpleBarRef.current - ?.getScrollElement() - .removeEventListener('scroll', onScroll); - }; - }, [height, disableTrigger, onScrollEnd]); - return ( - - - {children} - - - ); -}; - -export default SimpleOverlay; diff --git a/src/components/simple-table/cell.tsx b/src/components/simple-table/cell.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/simple-table/header.tsx b/src/components/simple-table/header.tsx deleted file mode 100644 index 793fb71b..00000000 --- a/src/components/simple-table/header.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useIntl } from '@umijs/max'; -import React from 'react'; - -interface TableHeaderProps { - columns: any[]; -} -interface TableHeaderProps { - columns: any[]; -} -const TableHeader = ({ columns }: TableHeaderProps) => { - const intl = useIntl(); - return ( - - {columns.map((column: any, index: number) => { - return ( - - - {column.locale - ? intl.formatMessage({ id: column.title }) - : column.title} - - - ); - })} - - ); -}; -export default React.memo(TableHeader); diff --git a/src/components/simple-table/index.less b/src/components/simple-table/index.less deleted file mode 100644 index 75f13f3c..00000000 --- a/src/components/simple-table/index.less +++ /dev/null @@ -1,50 +0,0 @@ -.simple-table { - table-layout: auto; - width: 100%; - text-align: left; - - &.simple-table-bordered { - border-collapse: collapse; - border-spacing: 0; - - td { - border-bottom: 1px solid var(--color-white-light-1); - } - - th { - border-bottom: 1px solid var(--color-white-light-1); - } - } - - th { - height: 36px; - font-weight: 600; - } - - td { - color: var(--color-white-quaternary); - } - - .cell-span { - display: flex; - padding: 6px; - min-height: 32px; - } - - .cell-header { - font-weight: var(--font-weight-medium); - font-size: 13px; - } - - &.light { - th { - color: var(--ant-color-text); - border-bottom: 1px solid var(--ant-color-split); - } - - td { - color: var(--ant-color-text); - border-bottom: 1px solid var(--ant-color-split); - } - } -} diff --git a/src/components/simple-table/index.tsx b/src/components/simple-table/index.tsx deleted file mode 100644 index 4f8c53a0..00000000 --- a/src/components/simple-table/index.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import classNames from 'classnames'; -import React from 'react'; -import 'simplebar-react/dist/simplebar.min.css'; -import TableHeader from './header'; -import './index.less'; -import TableRow from './row'; - -export interface ColumnProps { - title: string; - key: string; - width?: string | number; - style?: React.CSSProperties; - render?: (data: { - dataIndex: string; - dataList?: any[]; - row: any; - rowIndex?: number; - colIndex?: number; - }) => any; - locale?: boolean; - colSpan?: (params: { - row: any; - rowIndex: number; - colIndex: number; - dataIndex: string; - dataList: any[]; - }) => number; - rowSpan?: (params: { - row: any; - rowIndex: number; - colIndex: number; - dataIndex: string; - dataList: any[]; - }) => number; -} - -interface SimpleTableProps { - theme?: 'dark' | 'light'; - maxHeight?: number | string; - columns: ColumnProps[]; - dataSource: any[]; - bordered?: boolean; - rowKey: string; -} -const SimpleTabel: React.FC = (props) => { - const { columns, dataSource, rowKey, theme, bordered = true } = props; - - return ( -
    - - - - - - {dataSource.map((item: any, index: number) => { - return ( - - ); - })} - -
    -
    - ); -}; - -export default SimpleTabel; diff --git a/src/components/simple-table/info-column.tsx b/src/components/simple-table/info-column.tsx deleted file mode 100644 index 2e36c290..00000000 --- a/src/components/simple-table/info-column.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; - -import { useIntl } from '@umijs/max'; -import { Divider } from 'antd'; - -interface InfoColumnProps { - fieldList: { - label: string; - key: string; - locale?: boolean; - render?: (val: any, data: any) => any; - }[]; - style?: React.CSSProperties; - data: Record; -} -const InfoColumn: React.FC = (props) => { - const { data, fieldList, style } = props; - - const intl = useIntl(); - - return ( - - {fieldList.map((item, index) => { - return ( - - - - {' '} - {item.locale - ? intl.formatMessage({ id: item.label }) - : item.label} - - - {' '} - {item.render?.(data[item.key], data) ?? data[item.key]} - - - {index < fieldList.length - 1 ? ( - - ) : null} - - ); - })} - - ); -}; - -export default InfoColumn; diff --git a/src/components/simple-table/row.tsx b/src/components/simple-table/row.tsx deleted file mode 100644 index 330ca1dc..00000000 --- a/src/components/simple-table/row.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { useMemo } from 'react'; - -interface TableRowProps { - row: any; - columns: any; - rowIndex: number; - dataList: any[]; -} - -interface TableCellProps { - row: any; - column: any; - rowIndex: number; - colIndex: number; - dataList: any[]; -} -const TableCell: React.FC = (props: TableCellProps) => { - const { row, column, rowIndex, colIndex, dataList } = props; - - const renderContent = useMemo(() => { - return column.render - ? column.render({ - dataIndex: column.key, - dataList: dataList, - row: row, - rowIndex, - colIndex: colIndex - }) - : row[column.key]; - }, [column, row, rowIndex, colIndex, dataList]); - - if (renderContent === null && (column.colSpan || column.rowSpan)) { - return null; - } - - return ( - - - {column.render - ? column.render({ - dataIndex: column.key, - dataList: dataList, - row: row, - rowIndex, - colIndex: colIndex - }) - : row[column.key]} - - - ); -}; - -const TableRow = ({ row, columns, rowIndex, dataList }: TableRowProps) => { - return ( - - {columns.map((column: any, index: number) => { - return ( - - ); - })} - - ); -}; - -export default TableRow; diff --git a/src/components/speech-content/audio-player.tsx b/src/components/speech-content/audio-player.tsx deleted file mode 100644 index a85738b2..00000000 --- a/src/components/speech-content/audio-player.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import _ from 'lodash'; -import React, { - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useRef -} from 'react'; -import WaveSurfer, { WaveSurferOptions } from 'wavesurfer.js'; - -interface AudioPlayerProps { - autoplay: boolean; - audioUrl: string; - speed: number; - ref?: any; - height?: number; - width?: number; - onReady?: (duration: number) => void; - onClick?: (value: number) => void; - onFinish?: () => void; - onAnalyse?: (analyseData: any, frequencyBinCount: any) => void; - onAudioprocess?: (current: number) => void; - onPlay?: () => void; - onPause?: () => void; -} - -const AudioPlayer: React.FC< - AudioPlayerProps & Omit -> = forwardRef((props, ref) => { - const { autoplay, audioUrl, speed = 1, ...rest } = props; - const wavesurfer = useRef(null); - const container = useRef(null); - const audioContext = useRef(null); - const analyser = useRef(null); - const dataArray = useRef(null); - const mediaElement = useRef(null); - - const initAudioContext = useCallback(() => { - audioContext.current = new ( - window.AudioContext || window.webkitAudioContext - )(); - - analyser.current = audioContext.current.createAnalyser(); - analyser.current.fftSize = 512; - dataArray.current = new Uint8Array(analyser.current.frequencyBinCount); - }, []); - - const generateVisualData = useCallback(() => { - const source = audioContext.current.createMediaElementSource( - mediaElement.current - ); - source.connect(analyser.current); - analyser.current.connect(audioContext.current.destination); - }, []); - - const debouncePause = _.debounce(() => { - if (wavesurfer.current?.isPlaying()) { - wavesurfer.current?.pause(); - } - }, 100); - - const listenEvents = () => { - wavesurfer.current?.on('ready', (duration: number) => { - props.onReady?.(duration); - }); - - wavesurfer.current?.on('click', (value) => { - props.onClick?.(value); - }); - wavesurfer.current?.on('finish', () => { - props.onFinish?.(); - }); - wavesurfer.current?.on('audioprocess', (current: number) => { - props.onAudioprocess?.(current); - }); - wavesurfer.current?.on('seeking', (current: number) => { - console.log('seeking', current); - }); - - wavesurfer.current?.on('timeupdate', (current: number) => { - console.log('timeupdate', current); - }); - - wavesurfer.current?.on('play', () => { - analyser.current?.getByteFrequencyData(dataArray.current); - props.onAnalyse?.(dataArray.current, analyser); - props.onPlay?.(); - }); - - wavesurfer.current?.on('pause', () => { - analyser.current?.getByteFrequencyData(dataArray.current); - props.onAnalyse?.(dataArray.current, analyser); - props.onPause?.(); - }); - }; - - const createWavesurfer = () => { - wavesurfer.current?.destroy(); - wavesurfer.current = WaveSurfer.create({ - container: container.current, - url: audioUrl, - autoplay: autoplay, - audioRate: speed, - waveColor: '#4096ff', - progressColor: 'rgb(100, 0, 100)', - height: 60, - barWidth: 2, - barGap: 1, - barRadius: 2, - interact: true, - cursorWidth: 0, - ...rest - }); - - mediaElement.current = wavesurfer.current?.getMediaElement(); - - initAudioContext(); - generateVisualData(); - listenEvents(); - }; - - const destroyWavesurfer = () => { - if (wavesurfer.current) { - wavesurfer.current.destroy(); - } - }; - - const play = async () => { - if (wavesurfer.current) { - wavesurfer.current.play(); - } - }; - const isPlaying = () => { - if (wavesurfer.current) { - wavesurfer.current.isPlaying(); - } - }; - - const playPause = () => { - if (wavesurfer.current) { - wavesurfer.current.playPause(); - } - }; - - const debounceSeekTo = _.debounce((value: number) => { - if (wavesurfer.current) { - wavesurfer.current.seekTo(value); - } - }, 50); - - const debounceSetTime = _.debounce((value: number) => { - if (wavesurfer.current) { - wavesurfer.current.setTime(value); - } - }, 50); - - const seekTo = (value: number) => { - if (wavesurfer.current) { - debounceSeekTo(value); - } - }; - const setTime = (value: number) => { - if (wavesurfer.current) { - debounceSetTime(value); - } - }; - - const seekAndPlay = (value: number) => { - if (wavesurfer.current) { - wavesurfer.current.seekTo(value); - wavesurfer.current.once('seeking', () => { - wavesurfer.current - ?.play() - .catch((error) => console.error('Playback error:', error)); - }); - } - }; - - const duration = () => { - if (wavesurfer.current) { - return wavesurfer.current.getDuration(); - } - return 0; - }; - - const pause = () => { - if (wavesurfer.current) { - wavesurfer.current.pause(); - } - }; - - useImperativeHandle(ref, () => { - return { - play, - pause, - duration, - seekTo, - setTime, - playPause, - isPlaying, - wavesurfer - }; - }); - - useEffect(() => { - if (container.current && audioUrl) { - createWavesurfer(); - } - return () => { - destroyWavesurfer(); - }; - }, [audioUrl, container.current]); - return ( -
    - ); -}); - -export default AudioPlayer; diff --git a/src/components/speech-content/index.tsx b/src/components/speech-content/index.tsx deleted file mode 100644 index 6410954e..00000000 --- a/src/components/speech-content/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import SpeechItem from './speech-item'; - -interface SpeechContentProps { - dataList: any[]; - loading?: boolean; - onPlay?: () => void; - onPause?: () => void; - playerRef?: React.RefObject; - isPlaying?: boolean; - isStream?: boolean; - analyserData?: { - data: Uint8Array; - analyser: any; - }; -} - -const SpeechContent: React.FC = (props) => { - return ( -
    - {props.dataList.map((item) => ( - - ))} -
    - ); -}; - -export default SpeechContent; diff --git a/src/components/speech-content/speech-item.tsx b/src/components/speech-content/speech-item.tsx deleted file mode 100644 index 7c8afef6..00000000 --- a/src/components/speech-content/speech-item.tsx +++ /dev/null @@ -1,305 +0,0 @@ -import AudioAnimation from '@/components/audio-animation'; -import { - DownloadOutlined, - PauseCircleOutlined, - PlayCircleOutlined -} from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Slider, Tooltip } from 'antd'; -import dayjs from 'dayjs'; -import _, { throttle } from 'lodash'; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState -} from 'react'; -import RawAudioPlayer from '../audio-player/raw-audio-player'; -import './styles/index.less'; -import './styles/slider-progress.less'; - -const audioFormat = { - 'audio/mpeg': 'mp3', - 'audio/wav': 'wav', - 'audio/ogg': 'ogg', - 'audio/webm': 'webm', - 'audio/aac': 'aac', - 'audio/x-flac': 'flac', - 'audio/pcm': 'pcm', - 'audio/flac': 'flac', - 'audio/x-wav': 'wav', - 'audio/L16': 'pcm', - 'audio/opus': 'opus' -}; - -interface SpeechContentProps { - prompt: string; - autoplay: boolean; - voice: string; - format: string; - speed: number; - audioUrl: string; - onPlay?: () => void; - onPause?: () => void; - isStream?: boolean; - isPlaying?: boolean; - playerRef?: React.RefObject; - analyserData?: { - data: Uint8Array; - analyser: any; - }; -} -const SpeechItem: React.FC = (props) => { - const { isStream } = props; - console.log( - 'Rendering SpeechItem with props:', - props.isStream, - props.analyserData - ); - const intl = useIntl(); - const [isPlay, setIsPlay] = useState(props.autoplay || props.isPlaying); - const [duration, setDuration] = useState(0); - const [animationSize, setAnimationSize] = useState({ width: 900, height: 0 }); - const [currentTime, setCurrentTime] = useState(0); - const [audioChunks, setAudioChunks] = useState({ - data: new Uint8Array(128), - analyser: null - }); - const wrapper = useRef(null); - const ref = useRef(null); - - useEffect(() => { - setIsPlay(props.autoplay || props.isPlaying); - }, [props.autoplay, props.isPlaying]); - - const isPCMStream = useMemo(() => { - return props.audioUrl?.startsWith('pcm-stream://'); - }, [props.audioUrl]); - - // Sync internal ref with external playerRef if provided - React.useEffect(() => { - if (props.playerRef) { - (props.playerRef as any).current = ref.current; - } - }, [props.playerRef, ref.current]); - - const onPause = () => { - ref.current?.pause(); - props.onPause?.(); - }; - - const onPlay = async () => { - await ref.current?.wavesurfer.current?.play(); - props.onPlay?.(); - }; - - const handlePlay = async () => { - try { - if (ref.current?.wavesurfer.current?.isPlaying()) { - onPause(); - setIsPlay(false); - return; - } else { - await onPlay(); - setIsPlay(true); - } - } catch (error) { - console.log('error:', error); - } - }; - - const handleOnAnalyse = useCallback((data: any, analyser: any) => { - setAudioChunks((pre: any) => { - return { - data: data, - analyser: analyser - }; - }); - }, []); - - const handleOnFinish = useCallback(() => { - setIsPlay(false); - }, []); - - const handleOnPlay = useCallback(() => { - setIsPlay(true); - }, []); - - const handleOnPause = useCallback(() => { - setIsPlay(false); - }, []); - - const throttleUpdateCurrentTime = throttle((current: number) => { - setCurrentTime(current); - }, 100); - - const handleOnAudioprocess = (current: number) => { - throttleUpdateCurrentTime(current); - }; - - const handleAnimationResize = useCallback((size: any) => { - setAnimationSize({ - width: size.width, - height: size.height - }); - }, []); - - const debounceSeek = _.debounce((value: number) => { - ref.current?.seekTo(value / duration); - setCurrentTime(value); - }, 200); - - const handleSliderChange = (value: number) => { - debounceSeek(value); - }; - - const handleReady = useCallback((duration: number) => { - setDuration(duration); - }, []); - - const handlOnChangeComplete = useCallback((value: number) => { - ref.current?.seekTo(value / duration); - setCurrentTime(value); - }, []); - - const convertFormat = () => { - if (props.format === 'pcm') { - return 'wav'; - } - return props.format; - }; - - const onDownload = useCallback(() => { - const url = props.audioUrl || ''; - const filename = `audio-${dayjs().format('YYYYMMDDHHmmss')}.${convertFormat()}`; - - const link = document.createElement('a'); - link.href = url; - link.download = filename; - document.body.appendChild(link); - link.click(); - link.remove(); - }, [props.audioUrl, props.format]); - - console.log('isPCMStream:', isPCMStream, isPlay); - - console.log('props.analyserData:', props.analyserData); - - const renderPlayerActions = () => { - if (isPCMStream) { - return null; - } - return ( -
    - -
    - - {props.format} - - - {_.round(currentTime, 2) || _.round(duration, 2)} - -
    - - - - - - -
    -
    -
    - ); - }; - - return ( -
    -
    -
    - <> - {/* {!isPCMStream && ( - - )} */} - {!isPCMStream && ( - - )} - {isPlay && - (props.analyserData?.analyser?.current || - audioChunks.analyser?.current) && ( - - )} - -
    -
    - {renderPlayerActions()} -
    - ); -}; - -export default SpeechItem; diff --git a/src/components/speech-content/styles/index.less b/src/components/speech-content/styles/index.less deleted file mode 100644 index 9d597344..00000000 --- a/src/components/speech-content/styles/index.less +++ /dev/null @@ -1,105 +0,0 @@ -.speech-item { - display: flex; - justify-content: flex-start; - align-items: center; - width: 100%; - - .voice { - width: 80px; - display: flex; - justify-content: flex-start; - align-items: center; - gap: 5px; - - .text { - display: flex; - padding: 2px 4px; - border-radius: 4px; - border: 1px solid var(--ant-color-border); - } - } - - .wrapper { - flex: 1; - display: flex; - justify-content: flex-start; - align-items: center; - - .audio-container { - flex: 1; - } - - .format { - display: flex; - padding-left: 5px; - } - } - - audio { - flex: 1; - } -} - -.prompt-box { - padding-left: 80px; - - .prompt { - margin-top: 16px; - padding: 10px; - border-radius: var(--border-radius-base); - background-color: var(--ant-color-fill-quaternary); - } -} - -.speech-actions { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 10px; - // padding-left: 80px; - - .actions { - display: flex; - justify-content: flex-start; - align-items: center; - gap: 15px; - - .anticon { - font-size: 14px; - } - } - - .duration { - display: flex; - justify-content: center; - width: 100px; - } - - .tags { - display: flex; - justify-content: flex-start; - align-items: center; - - .item { - display: flex; - justify-content: center; - align-items: center; - padding: 2px; - border-radius: 4px; - color: var(--ant-color-text-tertiary); - } - - .splitor { - display: flex; - width: 1px; - height: 1px; - border-radius: 2px; - margin: 0 8px; - background-color: var(--ant-color-fill-content-hover); - } - } -} - -.audio-container { - pointer-events: none; -} diff --git a/src/components/speech-content/styles/slider-progress.less b/src/components/speech-content/styles/slider-progress.less deleted file mode 100644 index 1db18ce7..00000000 --- a/src/components/speech-content/styles/slider-progress.less +++ /dev/null @@ -1,21 +0,0 @@ -.slider-progress { - &:hover { - .ant-slider-track { - background-color: var(--ant-blue-5); - } - } - - .ant-slider-rail { - border-radius: var(--border-radius-base); - height: 2px; - } - - .ant-slider-track { - background-color: var(--ant-blue-5); - height: 2px; - } - - .ant-slider-handle { - display: none; - } -} diff --git a/src/components/status-icon/error.tsx b/src/components/status-icon/error.tsx deleted file mode 100644 index dce49ac6..00000000 --- a/src/components/status-icon/error.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { CloseOutlined } from '@ant-design/icons'; -import { createStyles } from 'antd-style/lib/functions'; - -const useStyles = createStyles(({ token, css }) => ({ - errorIcon: css` - display: flex; - align-items: center; - justify-content: center; - width: 64px; - height: 64px; - border-radius: 50%; - background-color: ${token.colorErrorBgActive}; - color: ${token.colorError}; - ` -})); - -const ErrorIcon: React.FC<{ size?: number }> = ({ size }) => { - const { styles } = useStyles(); - return ( -
    - -
    - ); -}; - -export default ErrorIcon; diff --git a/src/components/status-tag/copy-btn.less b/src/components/status-tag/copy-btn.less deleted file mode 100644 index f0b3b9c1..00000000 --- a/src/components/status-tag/copy-btn.less +++ /dev/null @@ -1,27 +0,0 @@ -:local(.status-content-wrapper) { - &:hover { - :global(.copy-button-wrapper) { - display: flex; - flex-direction: column; - align-items: center; - justify-content: flex-start; - } - } - - :global { - .copy-button-wrapper { - display: none; - background-color: rgba(255, 255, 255, 20%); - position: absolute; - z-index: 10; - right: 0; - top: 0; - padding: 2px; - border-radius: 0 4px; - } - - .simplebar-content { - width: max-content; - } - } -} diff --git a/src/components/status-tag/index.less b/src/components/status-tag/index.less deleted file mode 100644 index 22954e9a..00000000 --- a/src/components/status-tag/index.less +++ /dev/null @@ -1,53 +0,0 @@ -.status-tag { - position: relative; - display: flex; - justify-content: center; - align-items: center; - padding-inline: 7px; - border-radius: 20px; - min-width: 76px; - width: max-content; - height: 24px; - font-size: 12px; - font-weight: 400; - overflow: hidden; - - .txt { - display: flex; - align-items: center; - gap: 4px; - - &.err { - cursor: default; - } - } - - &.download { - border: 1px solid var(--ant-color-success-border-hover) !important; - } - - .download { - display: flex; - justify-content: center; - align-items: center; - position: absolute; - left: 0; - top: 0; - bottom: 0; - height: 100%; - background-color: var(--ant-color-success-border); - } - - .progress { - position: relative; - z-index: 10; - color: var(--ant-color-success); - } -} - -.tooltip-scrollbar { - .simplebar-scrollbar::before { - width: var(--scrollbar-size); - background: var(--scrollbar-handle-light-bg); - } -} diff --git a/src/components/status-tag/index.tsx b/src/components/status-tag/index.tsx deleted file mode 100644 index 6728666d..00000000 --- a/src/components/status-tag/index.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import { StatusColorMap } from '@/config'; -import { StatusType } from '@/config/types'; -import { InfoCircleOutlined } from '@ant-design/icons'; -import { Button, Divider, Tooltip } from 'antd'; -import classNames from 'classnames'; -import _ from 'lodash'; -import React, { useMemo } from 'react'; -import 'simplebar-react/dist/simplebar.min.css'; -import styled from 'styled-components'; -import CopyButton from '../copy-button'; -import { TooltipOverlayScroller } from '../overlay-scroller'; -import CopyStyle from './copy-btn.less'; -import './index.less'; - -const Text = styled.span` - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -`; - -const linkReg = /(.*?)<\/a>/g; -export const StatusMaps = { - transitioning: 'blue', - error: 'red', - warning: 'orange', - success: 'success', - inactive: 'inactive' -}; - -type StatusTagProps = { - style?: React.CSSProperties; - statusValue: { - status: StatusType; - text: string; - message?: string; - }; - type?: 'tag' | 'circle'; - download?: { - percent: number; - }; - suffix?: React.ReactNode; - maxTooltipWidth?: number; - extra?: React.ReactNode; - actions?: { - label: string; - icon?: React.ReactNode; - key: string; - onClick?: () => void; - render?: () => React.ReactNode; - }[]; -}; - -const StatusTag: React.FC = ({ - style, - statusValue, - download, - extra, - actions = [], - maxTooltipWidth = 250, - suffix -}) => { - const { text, status } = statusValue; - - const statusColor = useMemo<{ - text: string; - bg: string; - border?: string; - }>(() => { - return StatusColorMap[status]; - }, [status]); - - const hasLink = useMemo(() => { - if (!statusValue.message) return false; - return linkReg.test(statusValue.message || ''); - }, [statusValue.message]); - - const statusMessage = useMemo(() => { - if (!statusValue.message) return ''; - const link = statusValue.message?.match(linkReg); - if (link) { - return statusValue.message?.replace( - linkReg, - `$2` - ); - } - return statusValue.message; - }, [statusValue.message]); - - const renderContent = () => { - const percent = download?.percent || 0; - - if (download && percent > 0 && percent <= 100) { - return ( - <> - - {_.round(download?.percent, 0) || 0}% - - - - ); - } - return {text}; - }; - - const renderTitle = useMemo(() => { - return ( -
    -
    - - {actions?.map((item) => { - return ( -
    - - - - -
    - ); - })} -
    - -
    - {hasLink ? ( - - ) : ( - statusMessage - )} - {extra && {extra}} -
    -
    - ); - }, [statusValue]); - - return ( - - {statusValue.message ? ( - - - - {renderContent()} - {suffix && {suffix}} - - - ) : ( - - {renderContent()} - {suffix && {suffix}} - - )} - - ); -}; - -export default StatusTag; diff --git a/src/components/tags-wrapper/index.less b/src/components/tags-wrapper/index.less deleted file mode 100644 index c87c10b5..00000000 --- a/src/components/tags-wrapper/index.less +++ /dev/null @@ -1,33 +0,0 @@ -.tags-wrapper { - display: flex; - width: 100%; - overflow: hidden; - - .more { - display: flex; - align-items: center; - justify-content: center; - padding: 2px 6px; - border-radius: 4px; - font-size: 12px; - height: 22px; - opacity: 0.7; - } - - .tags-content { - display: flex; - } -} - -.tags-wrapper-dropdown { - .ant-dropdown-menu { - .ant-dropdown-menu-item { - background-color: transparent; - cursor: default; - - &:hover { - background-color: transparent; - } - } - } -} diff --git a/src/components/tags-wrapper/index.tsx b/src/components/tags-wrapper/index.tsx deleted file mode 100644 index 6c85b653..00000000 --- a/src/components/tags-wrapper/index.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { MoreOutlined } from '@ant-design/icons'; -import { Dropdown, Tag } from 'antd'; -import _ from 'lodash'; -import ResizeObserver from 'rc-resize-observer'; -import React, { useEffect, useRef, useState } from 'react'; -import './index.less'; - -interface TagsWrapperProps { - gap?: number; - dataList: any[]; - renderTag: (item: any, index?: number) => React.ReactNode; -} - -const TagsWrapper: React.FC = (props) => { - const { gap = 0, dataList, renderTag } = props; - const tagsContentRef = useRef(null); - const [hiddenIndices, setHiddenIndices] = useState({ - start: 0, - end: dataList.length - }); - const wrapperRef = useRef(null); - const moreBtnRef = useRef(null); - const moreButtonWidth = useRef(0); - const nodeSizeList = useRef([]); - - const calculateHiddenIndices = () => { - const wrapperWidth = wrapperRef.current?.offsetWidth || 0; - const childNodes = tagsContentRef.current?.childNodes; - let sizeList = nodeSizeList.current; - - if (!sizeList.length && childNodes?.length) { - sizeList = _.map(childNodes, (node: HTMLDivElement, index: number) => { - if (index === childNodes.length - 1) { - return node?.offsetWidth; - } - return node?.offsetWidth + gap; - }); - nodeSizeList.current = sizeList; - } - - if (wrapperWidth === 0 || !sizeList.length) return; - - // cache more button width - if (moreBtnRef.current?.offsetWidth) { - moreButtonWidth.current = moreBtnRef.current?.offsetWidth + gap; - } - - let totalWidth = 0; - let start = 0; - let end = dataList.length; - - for (let i = 0; i < sizeList.length; i++) { - const nodeWidth = sizeList[i]; - - if (totalWidth + moreButtonWidth.current >= wrapperWidth) { - end = i - 1 < 0 ? 0 : i - 1; - break; - } - totalWidth += nodeWidth; - - if (totalWidth >= wrapperWidth) { - end = i; - break; - } - } - - if (hiddenIndices.start !== start || hiddenIndices.end !== end) { - setHiddenIndices({ - start, - end - }); - } - }; - - const handleClick = (data: any) => { - data.domEvent?.stopPropagation(); - }; - - useEffect(() => { - if (tagsContentRef.current) { - calculateHiddenIndices(); - } - }, [dataList, gap]); - - const handleContentResize = _.throttle(() => { - calculateHiddenIndices(); - }, 200); - - return ( - -
    - -
    - {_.map( - _.slice(dataList, hiddenIndices.start, hiddenIndices.end), - (item: any, index: number) => { - return {renderTag?.(item, index)}; - } - )} -
    -
    - {hiddenIndices.end < dataList.length && ( - { - return { - label: renderTag?.(item, index), - key: index, - onClick: handleClick - }; - } - ) - }} - > - - - - - )} -
    -
    - ); -}; - -export default TagsWrapper; diff --git a/src/components/tags-wrapper/more-dropdown.tsx b/src/components/tags-wrapper/more-dropdown.tsx deleted file mode 100644 index 6634cc39..00000000 --- a/src/components/tags-wrapper/more-dropdown.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { MoreOutlined } from '@ant-design/icons'; -import { Dropdown, Tag } from 'antd'; -import React from 'react'; - -interface MoreDropdownProps { - items: any[]; -} - -const MoreDropdown: React.FC = (props) => { - const { items } = props; - return ( - <> - {items && items.length > 0 ? ( - - - - - - ) : null} - - ); -}; - -export default React.memo(MoreDropdown); diff --git a/src/components/tags-wrapper/theme-tag.tsx b/src/components/tags-wrapper/theme-tag.tsx deleted file mode 100644 index 81749124..00000000 --- a/src/components/tags-wrapper/theme-tag.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import useUserSettings from '@/hooks/use-user-settings'; -import { Tag, TagProps } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -const TagWrapper = styled(Tag)` - display: flex; - align-items: center; - justify-content: center; - padding: 2px 6px; - border-radius: 4px; - font-size: 12px; - height: 22px; - opacity: 0.7; - margin: 0; -`; - -const ThemeTag: React.FC = ({ - opacity, - style, - children, - ...restProps -}) => { - const { userSettings } = useUserSettings(); - const { isDarkTheme } = userSettings; - return ( - - {children} - - ); -}; - -ThemeTag.displayName = 'ThemeTag'; - -export default ThemeTag; diff --git a/src/components/templates/card-list.tsx b/src/components/templates/card-list.tsx index 6311b588..37974e47 100644 --- a/src/components/templates/card-list.tsx +++ b/src/components/templates/card-list.tsx @@ -1,7 +1,9 @@ -import ResizeContainer from '@/components/resize-container'; -import CardSkeleton from '@/components/templates/card-skelton'; -import InfiniteScroller from '@/pages/_components/infinite-scroller'; -import { useScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context'; +import { + InfiniteScroller, + ResizeContainer, + TemplateCardSkeleton +} from '@gpustack/core-ui'; +import { useScrollerContext } from '@gpustack/core-ui/lib/components/infinite-scroller/use-scroller-context'; import { Spin } from 'antd'; import React from 'react'; import styled from 'styled-components'; @@ -49,7 +51,7 @@ const ListSkeleton: React.FC<{ root: 'skelton-wrapper' }} > - {isFirst && } + {isFirst && } )} diff --git a/src/components/templates/card-skelton.tsx b/src/components/templates/card-skelton.tsx deleted file mode 100644 index ffbf81a2..00000000 --- a/src/components/templates/card-skelton.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Skeleton } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; -import ResizeContainer from '../resize-container'; - -const SkeletonWrapper = styled.div` - .ant-skeleton-paragraph { - margin-bottom: 0; - } -`; - -interface CatalogSkeltonProps { - skeletonProps?: any; - skeletonStyle?: React.CSSProperties; -} - -const CardSkelton: React.FC = (props) => { - return ( - ( - - - - )} - > - ); -}; - -export default CardSkelton; diff --git a/src/components/templates/card.tsx b/src/components/templates/card.tsx deleted file mode 100644 index c93edb07..00000000 --- a/src/components/templates/card.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import classNames from 'classnames'; -import React from 'react'; -import styled from 'styled-components'; - -interface CardProps { - height?: string | number; - className?: string; - children?: React.ReactNode; - clickable?: boolean; - ghost?: boolean; - header?: React.ReactNode; - footer?: React.ReactNode; - icon?: React.ReactNode; - active?: boolean; - hoverable?: boolean; - disabled?: boolean; - onClick?: () => void; -} - -const CardWrapper = styled.div.attrs({ - className: 'template-card-wrapper' -})` - overflow: hidden; - display: flex; - padding: 16px 16px; - justify-content: flex-start; - align-items: center; - border: 1px solid var(--ant-color-border); - border-radius: var(--ant-border-radius-lg); - cursor: default; - width: 100%; - &.clickable:hover:not(.disabled) { - background-color: var(--ant-color-fill-tertiary); - transition: background-color 0.2s ease; - } - - &.hoverable:hover:not(.disabled) { - background-color: var(--ant-color-fill-tertiary); - transition: background-color 0.2s ease; - } - - &.ghost { - background-color: transparent; - } - - &.active { - background-color: var(--ant-color-fill-tertiary); - } - - &.clickable:not(.disabled) { - cursor: pointer; - } - &.disabled { - cursor: default; - opacity: 0.6; - pointer-events: none; - border-style: dashed; - } -`; - -const CardContent = styled.div.attrs({ - className: 'template-card-content' -})` - width: 100%; - flex: 1; - color: var(--ant-color-text-tertiary); -`; - -const Inner = styled.div.attrs({ - className: 'template-card-inner' -})` - display: flex; - width: 100%; - flex-direction: column; - justify-content: flex-start; - gap: 8px; - height: 100%; -`; - -const Icon = styled.div.attrs({ - className: 'template-card-icon' -})` - display: flex; - align-items: center; - margin-right: 16px; - font-size: 32px; -`; - -const Header = styled.div.attrs({ - className: 'template-card-header' -})` - font-weight: bold; - font-size: var(--font-size-base); - display: flex; - align-items: center; - justify-content: space-between; -`; - -const Card: React.FC = (props) => { - const { - className, - height, - children, - clickable = true, - ghost = false, - header, - footer, - icon, - active, - disabled, - hoverable, - onClick - } = props; - - const handleClick = () => { - if (disabled || !clickable) return; - onClick?.(); - }; - - return ( - - {icon && {icon}} - - {header &&
    {header}
    } - {children && {children}} - {footer} -
    -
    - ); -}; - -export default Card; diff --git a/src/components/theme-toggle/theme-drop-actions.tsx b/src/components/theme-toggle/theme-drop-actions.tsx index fff87157..27558d89 100644 --- a/src/components/theme-toggle/theme-drop-actions.tsx +++ b/src/components/theme-toggle/theme-drop-actions.tsx @@ -1,9 +1,9 @@ import useUserSettings from '@/hooks/use-user-settings'; import { MoonOutlined, SunOutlined } from '@ant-design/icons'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Dropdown } from 'antd'; import { createStyles } from 'antd-style'; -import IconFont from '../icon-font'; const useStyles = createStyles(({ token, css }) => ({ inner: css` diff --git a/src/components/tooltip-list/index.tsx b/src/components/tooltip-list/index.tsx deleted file mode 100644 index f9b1a37a..00000000 --- a/src/components/tooltip-list/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useIntl } from '@umijs/max'; -import React from 'react'; -import styled from 'styled-components'; - -const UL = styled.ul` - list-style: none; - padding-left: 0; - margin: 0; - display: flex; - flex-direction: column; - li { - display: flex; - flex-direction: column; - .title { - font-weight: 600; - color: var(--ant-color-text-light-solid); - } - .content { - color: var(--color-white-tertiary); - display: inline-flex; - } - } -`; - -interface TooltipListProps { - list: { title: any; tips: string }[]; -} - -const TooltipList: React.FC = (props) => { - const intl = useIntl(); - const { list } = props; - return ( -
      - {list.map((item, index: number) => { - return ( -
    • - - {item.title?.locale - ? intl.formatMessage({ id: item.title?.text || '' }) - : item.title} - : - - - {intl.formatMessage({ id: item.tips })} - -
    • - ); - })} -
    - ); -}; - -export default TooltipList; diff --git a/src/components/transition/index.less b/src/components/transition/index.less deleted file mode 100644 index c5114c25..00000000 --- a/src/components/transition/index.less +++ /dev/null @@ -1,45 +0,0 @@ -.transition-wrapper { - border-radius: 8px; - display: flex; - flex-direction: column; - overflow: hidden; - - &.bordered { - border-width: var(--ant-line-width); - border-style: var(--ant-line-type); - border-color: var(--ant-color-border); - background-color: var(--color-white-1); - } - - &.filled { - border-color: var(--ant-color-border); - - .transition-content-wrapper { - background-color: var(--color-fill-1); - } - } - - .header { - background-color: var(--color-fill-1); - cursor: pointer; - padding: 8px 16px; - } - - .transition-content-wrapper { - overflow: hidden; - transition: all 300ms ease-in-out; - - .transition-content { - height: max-content; - background-color: var(--color-white-1); - border-radius: var(--border-radius-base); - } - } - - .ant-input { - &::-webkit-scrollbar-track { - width: 0 !important; - color: transparent; - } - } -} diff --git a/src/components/transition/index.tsx b/src/components/transition/index.tsx deleted file mode 100644 index 8c611915..00000000 --- a/src/components/transition/index.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import classNames from 'classnames'; -import { - forwardRef, - useEffect, - useImperativeHandle, - useRef, - useState -} from 'react'; -import './index.less'; - -interface TransitionWrapProps { - minHeight?: number; - header?: React.ReactNode; - variant?: 'bordered' | 'filled'; - children: React.ReactNode; - setCollapsed?: (val: boolean) => void; - ref?: any; -} -const TransitionWrapper: React.FC = forwardRef( - (props, ref) => { - const { - minHeight = 50, - header, - variant = 'bordered', - children, - setCollapsed - } = props; - const [isOpen, setIsOpen] = useState(true); - const [height, setHeight] = useState(0); - const contentRef = useRef(null); - - useEffect(() => { - if (isOpen) { - setHeight(contentRef?.current?.scrollHeight || 0); - } else { - setHeight(0); - } - }, [isOpen]); - - const toggleOpen = () => { - setIsOpen(!isOpen); - setCollapsed?.(!isOpen); - }; - - const setHeightByContent = () => { - setHeight(contentRef?.current?.scrollHeight || 0); - }; - - useImperativeHandle(ref, () => { - return { - setHeightByContent - }; - }); - - return ( -
    -
    - {header} -
    -
    -
    {children}
    -
    -
    - ); - } -); - -export default TransitionWrapper; diff --git a/src/components/type-word-effect/index.tsx b/src/components/type-word-effect/index.tsx deleted file mode 100644 index 275fa057..00000000 --- a/src/components/type-word-effect/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect, useState } from 'react'; - -const TypingEffect: React.FC<{ text?: string }> = ({ text = '' }) => { - const [displayedText, setDisplayedText] = useState(''); - - useEffect(() => { - let index = 0; - const intervalId = setInterval(() => { - setDisplayedText((prev) => prev + text[index]); - index += 1; - if (index === text.length) { - clearInterval(intervalId); - } - }, 20); - - return () => clearInterval(intervalId); - }, [text]); - - return
    {displayedText}
    ; -}; - -export default TypingEffect; diff --git a/src/components/upload-audio/index.tsx b/src/components/upload-audio/index.tsx deleted file mode 100644 index 19d79599..00000000 --- a/src/components/upload-audio/index.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { UploadOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Tooltip, Upload, message } from 'antd'; -import React from 'react'; -import { convertFileSize } from '../../utils'; - -interface UploadAudioProps { - accept?: string; - maxCount?: number; - type?: 'text' | 'primary' | 'default'; - icon?: React.ReactNode; - size?: 'small' | 'middle' | 'large'; - shape?: 'circle' | 'round' | 'default'; - maxFileSize?: number; // in bytes - onChange?: (data: { file: any; fileList: any[] }) => void; -} - -const UploadAudio: React.FC = (props) => { - const [messageApi, contextHolder] = message.useMessage(); - const { icon, accept, type, size = 'large', shape = 'circle' } = props; - const intl = useIntl(); - const beforeUpload = (file: any) => { - return false; - }; - - const isFileSizeValid = (file: File) => { - if (props.maxFileSize && file.size > props.maxFileSize) { - messageApi.open({ - type: 'warning', - content: intl.formatMessage( - { id: 'playground.uploadfile.sizeError' }, - { size: `${convertFileSize(props.maxFileSize)}` } // Convert bytes to MB - ) - }); - return false; - } - return true; - }; - - const handleOnChange = (data: { file: any; fileList: any }) => { - if (!isFileSizeValid(data.file)) { - return; - } - props.onChange?.(data); - }; - - return ( - - -
    - -
    -
    - {contextHolder} -
    - ); -}; - -export default UploadAudio; diff --git a/src/components/util-bar/index.less b/src/components/util-bar/index.less deleted file mode 100644 index 37604d7f..00000000 --- a/src/components/util-bar/index.less +++ /dev/null @@ -1,17 +0,0 @@ -.util-bar-box { - width: 100%; - height: 100%; - display: flex; - justify-content: space-between; - flex-direction: column; - align-items: center; - - .title { - font-weight: var(--font-weight-medium); - padding: 20px 0; - } - - .ant-progress.ant-progress-circle .ant-progress-text { - font-size: 20px; - } -} diff --git a/src/components/util-bar/index.tsx b/src/components/util-bar/index.tsx deleted file mode 100644 index 2d1c172f..00000000 --- a/src/components/util-bar/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Progress } from 'antd'; -import './index.less'; - -interface UitilBarProps { - title?: string; - percent: number; - steps?: number; - gapDegree?: number; - strokeWidth?: number; - size?: number; - railColor?: string; - strokeColor?: string; -} -const UitilBar: React.FC = (props) => { - const { - percent, - steps = 10, - gapDegree = 170, - strokeWidth = 10, - title, - size = 150, - strokeColor, - railColor = 'rgba(221,221,221,.5)' - } = props; - - const strokeColorFunc = (percent: number) => { - if (percent <= 50) { - return 'var(--color-chart-green)'; - } - if (percent <= 80) { - return 'var(--color-chart-glod)'; - } - return 'var(--color-chart-red)'; - }; - return ( -
    - {title && {title}} - -
    - ); -}; - -export default UitilBar; diff --git a/src/components/x-terminal/index.tsx b/src/components/x-terminal/index.tsx deleted file mode 100644 index 2b7791f1..00000000 --- a/src/components/x-terminal/index.tsx +++ /dev/null @@ -1,294 +0,0 @@ -import useUserSettings from '@/hooks/use-user-settings'; -import { FitAddon } from '@xterm/addon-fit'; -import { Terminal } from '@xterm/xterm'; -import '@xterm/xterm/css/xterm.css'; -import { createStyles } from 'antd-style'; -import _ from 'lodash'; -import qs from 'query-string'; -import React, { forwardRef, useEffect, useImperativeHandle } from 'react'; - -const useStyles = createStyles(({ token, css }) => ({ - wrap: css` - position: relative; - text-align: left; - .xterm { - height: 100%; - .xterm-viewport { - overflow-y: auto; - } - } - `, - terminal: css` - height: 100%; - padding: 5px; - overflow: hidden; - overflow: hidden; - background-color: var(--color-logs-bg); - border-radius: 0 0 8px 8px; - ` -})); - -const terminalEnvList = ['bash', 'sh', 'powershell', 'pwsh', 'cmd', 'bash']; - -const RECONNECT_MSG = '--- press Y to reconnect! ---'; - -const colorBg2 = 'rgb(33, 36, 39)'; - -interface XTerminalProps { - height: number; - url: string; -} - -const XTerminal: React.FC = forwardRef((props, ref) => { - const { height, url } = props; - const { styles } = useStyles(); - const { userSettings } = useUserSettings(); - const terminalRef = React.useRef(null); - const WrapperRef = React.useRef(null); - const terminalInstance = React.useRef(null); - const wssURL = React.useRef(''); - const terminalEnvIndex = React.useRef(0); - const terminalSocket = React.useRef(null); - const retryCount = React.useRef(5); - const totalRetry = React.useRef(5); - const first = React.useRef(true); - const loading = React.useRef(false); - const timer = React.useRef(null); - const toRetry = React.useRef(false); - const conReadyState = React.useRef(0); - const [statusCode, setStatusCode] = React.useState(0); - - const fitAddon = new FitAddon(); - - const setWssUrl = (flag?: boolean) => { - if (terminalEnvIndex.current >= terminalEnvList.length - 1) return; - if (flag) { - terminalEnvIndex.current = 0; - } else { - terminalEnvIndex.current += 1; - } - const params = qs.stringify({ - shell: terminalEnvList[terminalEnvIndex.current] - }); - wssURL.current = `${url}&${params}`; - }; - - // readyState: 0 1 2 3 - const isWsOpen = () => { - const readyState = - terminalSocket.current && terminalSocket.current.readyState; - return readyState === 1; - }; - - const resizeRemoteTerminal = () => { - const { cols, rows } = terminalInstance.current || {}; - if (isWsOpen()) { - terminalSocket.current?.send(`#{"width":${cols},"height":${rows}}#`); - } - }; - - const fitTerm = () => { - fitAddon.fit(); - resizeRemoteTerminal(); - }; - - const onResize = _.throttle(() => fitTerm(), 100); - - const removeResizeListener = () => { - window.removeEventListener('resize', onResize); - }; - - const destoryedTerm = () => { - removeResizeListener(); - terminalSocket.current?.close?.(); - }; - - const setData = (data: string) => { - return `${data}\x1B[1;3;31m\x1B[0m`; - }; - - const setErrorData = (data: string) => { - return `\x1b[31m${data}\x1b[m`; - }; - - const runRealTerminal = () => { - terminalInstance.current?.clear?.(); - loading.current = false; - toRetry.current = false; - }; - - const onWSReceive = (message: MessageEvent) => { - if (first.current === true) { - first.current = false; - resizeRemoteTerminal(); - } - - const data = { Data: message.data }; - conReadyState.current = terminalSocket.current?.readyState || 0; - - // const data = JSON.parse(message.data) || ''; - if (terminalInstance.current?.element) terminalInstance.current.focus(); - const output = data.Data; - terminalInstance.current?.write?.(setData(output)); - }; - - const closeRealTerminal = (data: any) => { - setStatusCode(_.get(data, 'code')); - conReadyState.current = terminalSocket.current?.readyState || 0; - if ([1011, 1006, 1000].includes(statusCode)) { - toRetry.current = true; - if (first.current) { - terminalInstance.current?.reset?.(); - } - if (!loading.current) { - terminalInstance.current?.write?.( - setData(`(${statusCode})${data.reason}\r\n`) - ); - terminalInstance.current?.write?.(setErrorData(`\r${RECONNECT_MSG}`)); - } - first.current = true; - } else if (data.reason) { - terminalInstance.current?.write?.( - setData(`(${statusCode})${data.reason}\r\n`) - ); - } - loading.current = false; - }; - - const errorRealTerminal = (ex: any) => { - let { message } = ex; - if (!message) { - message = 'disconnected!'; - toRetry.current = true; - first.current = true; - loading.current = false; - } - conReadyState.current = terminalSocket.current!.readyState; - terminalInstance.current?.write?.(setErrorData(`\r${message}`)); - }; - - const createWS = () => { - if (!props.url) return; - terminalInstance.current?.write?.(''); - setStatusCode(0); - terminalSocket.current = new WebSocket(wssURL.current); - terminalSocket.current.onopen = runRealTerminal; - terminalSocket.current.onmessage = onWSReceive; - terminalSocket.current.onclose = closeRealTerminal; - terminalSocket.current.onerror = errorRealTerminal; - }; - - const initWS = () => { - if (!terminalSocket.current) { - createWS(); - return; - } - terminalSocket.current?.close?.(); - createWS(); - }; - - const retry = () => { - loading.current = true; - terminalInstance.current?.reset?.(); - initWS(); - }; - - const registerTermHandler = () => { - terminalInstance.current?.onData((data: string) => { - if (isWsOpen()) { - terminalSocket.current?.send(data); - } - }); - terminalInstance.current?.onKey((e: any) => { - if (toRetry.current && e.domEvent.code === 'KeyY') { - retry(); - } - }); - }; - - const onTerminalResize = () => { - window.addEventListener('resize', onResize); - }; - - const initTerm = () => { - terminalInstance.current?.dispose?.(); - terminalInstance.current = new Terminal({ - lineHeight: 1.2, - fontSize: 12, - fontFamily: - "monospace,Menlo,Courier,'Courier New',Consolas,Monaco, 'Liberation Mono'", - theme: { - background: userSettings.theme === 'realDark' ? colorBg2 : '#181d28', - foreground: - userSettings.theme === 'realDark' - ? 'rgba(255, 255, 255, 0.7)' - : '#fff' - }, - cursorBlink: true, - cursorStyle: 'underline', - scrollback: 100, - tabStopWidth: 4 - }); - terminalInstance.current?.open?.(terminalRef.current!); - terminalInstance.current?.loadAddon?.(fitAddon); - fitAddon.fit(); - }; - - const init = () => { - setWssUrl(); - initWS(); - initTerm(); - registerTermHandler(); - onTerminalResize(); - }; - - const debounceCall = _.debounce(() => { - first.current = true; - loading.current = true; - setWssUrl(true); - initWS(); - }, 100); - - useEffect(() => { - if (!url) { - terminalInstance.current?.reset?.(); - terminalSocket.current?.close?.(); - terminalSocket.current = null; - } else { - // reset retry count - retryCount.current = totalRetry.current; - clearTimeout(timer.current); - - terminalInstance.current?.reset?.(); - debounceCall(); - } - return () => { - destoryedTerm(); - removeResizeListener(); - }; - }, [url]); - - useImperativeHandle(ref, () => ({ - fit: () => { - fitAddon.fit(); - } - })); - - return ( -
    -
    -
    - ); -}); - -export default XTerminal; diff --git a/src/hooks/use-chunk-request.ts b/src/hooks/use-chunk-request.ts index fc1d3216..38d59eee 100644 --- a/src/hooks/use-chunk-request.ts +++ b/src/hooks/use-chunk-request.ts @@ -143,7 +143,7 @@ const useSetChunkRequest = () => { total.current = e.total || 0; if (contentType === 'json') { - let currentRes = sliceData(response, e.loaded, loadedSize); + const currentRes = sliceData(response, e.loaded, loadedSize); workerRef.current.postMessage(currentRes); } else { handler(response); diff --git a/src/hooks/use-download-logs.tsx b/src/hooks/use-download-logs.tsx index 7b5cb90a..ba2db93b 100644 --- a/src/hooks/use-download-logs.tsx +++ b/src/hooks/use-download-logs.tsx @@ -1,5 +1,5 @@ import { HandlerOptions } from '@/hooks/use-chunk-fetch'; -import useDownloadStream from '@/hooks/use-download-stream'; +import { useDownloadStream } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Progress, notification } from 'antd'; import dayjs from 'dayjs'; diff --git a/src/layouts/error-boundary.tsx b/src/layouts/error-boundary.tsx index 66c23195..7e586e7d 100644 --- a/src/layouts/error-boundary.tsx +++ b/src/layouts/error-boundary.tsx @@ -2,7 +2,6 @@ import type { ErrorInfo } from 'react'; import React from 'react'; import ErrorResult from './error-result'; -// eslint-disable-next-line @typescript-eslint/ban-types class ErrorBoundary extends React.Component< { children?: React.ReactNode }, { hasError: boolean; errorInfo: string } @@ -15,7 +14,7 @@ class ErrorBoundary extends React.Component< componentDidCatch(error: any, errorInfo: ErrorInfo) { // You can also log the error to an error reporting service - // eslint-disable-next-line no-console + console.log(error, errorInfo); } diff --git a/src/layouts/extraRender.tsx b/src/layouts/extraRender.tsx index 1ec80d9d..1c49de78 100644 --- a/src/layouts/extraRender.tsx +++ b/src/layouts/extraRender.tsx @@ -1,6 +1,4 @@ import { GPUStackVersionAtom, UpdateCheckAtom } from '@/atoms/user'; -import DropDownActions from '@/components/drop-down-actions'; -import IconFont from '@/components/icon-font'; import VersionInfo, { modalConfig } from '@/components/version-info'; import externalLinks from '@/constants/external-links'; import useBodyScroll from '@/hooks/use-body-scroll'; @@ -12,6 +10,7 @@ import { HomeOutlined, ReadOutlined } from '@ant-design/icons'; +import { DropdownActions, IconFont } from '@gpustack/core-ui'; import { history, useIntl, useNavigate } from '@umijs/max'; import { Avatar, Button, Divider, Modal } from 'antd'; import { useAtom } from 'jotai'; @@ -292,7 +291,7 @@ export const ExtraContent = (props: { isDarkTheme?: boolean }) => { )} - + { style={{ color: 'var(--ant-color-text-tertiary)' }} /> - - + + { icon={} /> - + ); }; diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx index 5958106a..765fe7a3 100644 --- a/src/layouts/index.tsx +++ b/src/layouts/index.tsx @@ -1,21 +1,30 @@ import { routeCacheAtom, setRouteCache } from '@/atoms/route-cache'; import { userAtom } from '@/atoms/user'; import DarkMask from '@/components/dark-mask'; -import IconFont from '@/components/icon-font'; import routeCachekey from '@/config/route-cachekey'; -import { DEFAULT_ENTER_PAGE } from '@/config/settings'; +import { DEFAULT_ENTER_PAGE, GPUSTACK_API_BASE_URL } from '@/config/settings'; import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useUserSettings from '@/hooks/use-user-settings'; import useAddResource from '@/pages/dashboard/hooks/use-add-resource'; import { logout } from '@/pages/login/apis'; +import { + readColumnSettings, + readState, + writeColumnSettings, + writeState +} from '@/utils/localstore'; import { useAccessMarkedRoutes } from '@@/plugin-access'; import { useModel } from '@@/plugin-model'; import { ProLayout } from '@ant-design/pro-components'; +import { CoreUIProvider, IconFont } from '@gpustack/core-ui'; import { Outlet, dropByCacheKey, + getAllLocales, history, matchRoutes, + request, + setLocale, useAppData, useIntl, useLocation, @@ -23,7 +32,6 @@ import { type IRoute } from '@umijs/max'; import { Button, ConfigProvider, Modal, theme } from 'antd'; -import 'driver.js/dist/driver.css'; import { useAtom } from 'jotai'; import 'overlayscrollbars/overlayscrollbars.css'; import { useEffect, useMemo, useRef } from 'react'; @@ -73,7 +81,7 @@ const filterRoutes = ( return []; } - let newRoutes: NewRoute[] = []; + const newRoutes: NewRoute[] = []; for (const route of routes) { const newRoute = { ...route }; if (filterFn(route)) { @@ -158,7 +166,7 @@ export default (props: any) => { }; const dropRouteCache = (pathname: string) => { - for (let key of routeCache.keys()) { + for (const key of routeCache.keys()) { if (key !== pathname && !routeCache.get(key) && routeCachekey[key]) { dropByCacheKey(key); routeCache.delete(key); @@ -329,8 +337,6 @@ export default (props: any) => { }); }; - console.log('userConfig==========title', userConfig.title); - return ( { } }} > - - : } - menuContentRender={menuContentRender} - {...runtimeConfig} - ErrorBoundary={ErrorBoundary} > - + : } + menuContentRender={menuContentRender} + {...runtimeConfig} + ErrorBoundary={ErrorBoundary} > - {isNoContainerPage ? ( - - ) : ( - -
    - -
    -
    - )} -
    - {NoResourceModal} - {contextHolder} -
    + + {isNoContainerPage ? ( + + ) : ( + +
    + +
    +
    + )} +
    + {NoResourceModal} + {contextHolder} + +
    ); }; diff --git a/src/layouts/sider-menu.tsx b/src/layouts/sider-menu.tsx index dbe4257a..5a9bd0f1 100644 --- a/src/layouts/sider-menu.tsx +++ b/src/layouts/sider-menu.tsx @@ -1,5 +1,5 @@ -import IconFont from '@/components/icon-font'; import { CaretDownOutlined } from '@ant-design/icons'; +import { IconFont } from '@gpustack/core-ui'; import { Link, useLocation } from '@umijs/max'; import { Tooltip } from 'antd'; import { createStyles } from 'antd-style'; diff --git a/src/pages/_components/category-select.tsx b/src/pages/_components/category-select.tsx index 670ef10e..a04a9a49 100644 --- a/src/pages/_components/category-select.tsx +++ b/src/pages/_components/category-select.tsx @@ -1,4 +1,4 @@ -import SealSelect from '@/components/seal-form/seal-select'; +import { Select as SealSelect } from '@gpustack/core-ui'; import React from 'react'; import { categoryConfig } from './model-tag'; diff --git a/src/pages/_components/collapse-panel/index.tsx b/src/pages/_components/collapse-panel/index.tsx index 4f5edd2d..cb4f4705 100644 --- a/src/pages/_components/collapse-panel/index.tsx +++ b/src/pages/_components/collapse-panel/index.tsx @@ -1,4 +1,4 @@ -import IconFont from '@/components/icon-font'; +import { IconFont } from '@gpustack/core-ui'; import { Collapse, CollapseProps } from 'antd'; import React from 'react'; import styled from 'styled-components'; diff --git a/src/pages/_components/column-settings.tsx b/src/pages/_components/column-settings.tsx index 42f28bce..4984a9e0 100644 --- a/src/pages/_components/column-settings.tsx +++ b/src/pages/_components/column-settings.tsx @@ -1,9 +1,9 @@ -import OverlayScroller from '@/components/overlay-scroller'; import { readColumnSettings, writeColumnSettings } from '@/utils/localstore/index'; import { SettingOutlined } from '@ant-design/icons'; +import { OverlayScroller } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Checkbox, Col, Popover, Row, Tooltip } from 'antd'; import React, { useEffect } from 'react'; diff --git a/src/pages/_components/command-viewer/index.tsx b/src/pages/_components/command-viewer/index.tsx deleted file mode 100644 index 775e5333..00000000 --- a/src/pages/_components/command-viewer/index.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import CopyButton from '@/components/copy-button'; -import EditorWrap from '@/components/editor-wrap'; -import HighlightCode from '@/components/highlight-code'; -import SegmentLine from '@/components/segment-line'; -import React from 'react'; -import styled from 'styled-components'; - -interface ViewerProps { - code: string; - copyText?: string; - options?: Global.BaseOption[]; - defaultValue?: string; - headerHeight?: number; - showTitle?: boolean; - height?: number; - lang?: string; - onChange?: (value: string | number) => void; -} - -const Header = styled.div` - width: 100%; - padding-inline: 12px 10px; - display: flex; - align-items: center; - justify-content: space-between; - background-color: var(--color-editor-header-bg); -`; - -const CommandViewer: React.FC = (props) => { - const { - code, - copyText = '', - defaultValue, - options = [], - headerHeight = 40, - height = 380, - showTitle = false, - lang, - onChange - } = props || {}; - - const [value, setValue] = React.useState(defaultValue || ''); - - const handlOnChange = (value: string | number) => { - setValue(value as string); - onChange?.(value); - }; - - return ( - - - - - - } - > - - - ); -}; - -export default CommandViewer; diff --git a/src/pages/_components/doc-link.tsx b/src/pages/_components/doc-link.tsx index 672f8f14..1004fba6 100644 --- a/src/pages/_components/doc-link.tsx +++ b/src/pages/_components/doc-link.tsx @@ -1,4 +1,4 @@ -import IconFont from '@/components/icon-font'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button } from 'antd'; import React from 'react'; diff --git a/src/pages/_components/filter-form/index.tsx b/src/pages/_components/filter-form/index.tsx index 6e68fb58..ff9c108f 100644 --- a/src/pages/_components/filter-form/index.tsx +++ b/src/pages/_components/filter-form/index.tsx @@ -1,5 +1,5 @@ -import OverlayScroller from '@/components/overlay-scroller'; import { CloseOutlined } from '@ant-design/icons'; +import { OverlayScroller } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Form } from 'antd'; import classNames from 'classnames'; diff --git a/src/pages/_components/form-drawer.tsx b/src/pages/_components/form-drawer.tsx index bcc5dba7..e27f16d8 100644 --- a/src/pages/_components/form-drawer.tsx +++ b/src/pages/_components/form-drawer.tsx @@ -1,6 +1,4 @@ -import ModalFooter from '@/components/modal-footer'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; +import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui'; import { Tag } from 'antd'; import React from 'react'; diff --git a/src/pages/_components/model-tag.tsx b/src/pages/_components/model-tag.tsx index 8dee5275..9dd8c440 100644 --- a/src/pages/_components/model-tag.tsx +++ b/src/pages/_components/model-tag.tsx @@ -1,9 +1,9 @@ -import IconFont from '@/components/icon-font'; import { AudioOutlined, PictureOutlined, WechatWorkOutlined } from '@ant-design/icons'; +import { IconFont } from '@gpustack/core-ui'; import { Tag } from 'antd'; import { modelCategoriesMap } from '../llmodels/config'; diff --git a/src/pages/_components/page-breadcrumb/index.tsx b/src/pages/_components/page-breadcrumb/index.tsx index 0179eb02..7cdaa23e 100644 --- a/src/pages/_components/page-breadcrumb/index.tsx +++ b/src/pages/_components/page-breadcrumb/index.tsx @@ -1,4 +1,4 @@ -import IconFont from '@/components/icon-font'; +import { IconFont } from '@gpustack/core-ui'; import { Breadcrumb, type BreadcrumbProps } from 'antd'; import React from 'react'; import styled from 'styled-components'; diff --git a/src/pages/_components/pill-button-group/index.tsx b/src/pages/_components/pill-button-group/index.tsx index 150716cd..2b3f67ec 100644 --- a/src/pages/_components/pill-button-group/index.tsx +++ b/src/pages/_components/pill-button-group/index.tsx @@ -1,7 +1,6 @@ -import AutoTooltip from '@/components/auto-tooltip'; +import { AutoTooltip } from '@gpustack/core-ui'; import React from 'react'; import pillButtonCss from './styles.less'; - type Option = { label: string; value: string | number | null; diff --git a/src/pages/_components/scroll-spy-tabs/index.tsx b/src/pages/_components/scroll-spy-tabs/index.tsx index f3fb5596..881e96cb 100644 --- a/src/pages/_components/scroll-spy-tabs/index.tsx +++ b/src/pages/_components/scroll-spy-tabs/index.tsx @@ -1,4 +1,4 @@ -import SegmentLine from '@/components/segment-line'; +import { SegmentLine } from '@gpustack/core-ui'; import { useMemoizedFn } from 'ahooks'; import _ from 'lodash'; import React, { forwardRef, useImperativeHandle } from 'react'; diff --git a/src/pages/_components/select-panel/index.tsx b/src/pages/_components/select-panel/index.tsx deleted file mode 100644 index 85c17065..00000000 --- a/src/pages/_components/select-panel/index.tsx +++ /dev/null @@ -1,224 +0,0 @@ -import { SearchOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Button, Checkbox, Empty, Input } from 'antd'; -import React, { useEffect, useMemo, useState } from 'react'; -import styled from 'styled-components'; -import List from './list'; -import SelectedList from './selected-list'; - -const PanelWrapper = styled.div<{ $maxHeight?: number; $leftWidth?: number }>` - border: 1px solid var(--ant-color-border); - border-radius: var(--ant-border-radius); - overflow-y: auto; - max-height: ${({ $maxHeight }) => - $maxHeight ? `${$maxHeight + 2}px` : 'auto'}; -`; - -const Left = styled.div` - padding: 0; -`; -const Right = styled.div``; - -const Header = styled.div` - padding: 8px 12px 8px; - display: flex; - gap: 8px; - align-items: center; - justify-content: space-between; - border-bottom: 1px solid var(--ant-color-split); - background-color: var(--ant-color-fill-alter); -`; - -interface SelectPanelProps { - searchPlaceholder?: string; - height?: number; - leftWidth?: number; - options: Array<{ key: string; title: string }>; - selectedKeys: string[]; - notFoundContent?: React.ReactNode; - onSelectChange: (selectedKeys: string[]) => void; - styles?: { - container?: React.CSSProperties; - left?: React.CSSProperties; - right?: React.CSSProperties; - header?: React.CSSProperties; - }; -} - -const SelectPanel: React.FC = ({ - height = 300, - leftWidth = 260, - options, - selectedKeys, - searchPlaceholder, - notFoundContent, - styles, - onSelectChange -}) => { - const intl = useIntl(); - const [indeterminate, setIndeterminate] = React.useState(false); - const [checkAll, setCheckAll] = React.useState(false); - const [searchText, setSearchText] = useState(''); - - const showOptions = useMemo(() => { - return options.filter((item) => - item.title.toLowerCase().includes(searchText.toLowerCase()) - ); - }, [options, searchText]); - - const handleSearch = (e: React.ChangeEvent) => { - setSearchText(e.target.value); - }; - - const handleOnUnselect = ( - key: string, - newSelectedKeys: { key: string; title: string }[] - ) => { - onSelectChange(newSelectedKeys.map((item) => item.key)); - }; - - const handleCheckAllChange = (e: any) => { - const checked = e.target.checked; - setCheckAll(checked); - setIndeterminate(false); - if (checked) { - const allKeys = options - .filter((item) => - item.title.toLowerCase().includes(searchText.toLowerCase()) - ) - .map((item) => item.key); - onSelectChange(Array.from(new Set([...selectedKeys, ...allKeys]))); - } else { - const filteredKeys = options - .filter((item) => - item.title.toLowerCase().includes(searchText.toLowerCase()) - ) - .map((item) => item.key); - const newSelectedKeys = selectedKeys.filter( - (key) => !filteredKeys.includes(key) - ); - onSelectChange(newSelectedKeys); - } - }; - - const updateCheckStatus = (newSelectedKeys: string[]) => { - if (options.length === 0) { - setIndeterminate(false); - setCheckAll(false); - return; - } - const filteredOptions = options.filter((item) => - item.title.toLowerCase().includes(searchText.toLowerCase()) - ); - const filteredKeys = filteredOptions.map((item) => item.key); - const selectedFilteredKeys = newSelectedKeys.filter((key) => - filteredKeys.includes(key) - ); - setIndeterminate( - selectedFilteredKeys.length > 0 && - selectedFilteredKeys.length < filteredKeys.length - ); - setCheckAll(selectedFilteredKeys.length === filteredKeys.length); - }; - - const handleSelectChange = (newSelectedKeys: string[]) => { - onSelectChange(newSelectedKeys); - updateCheckStatus(newSelectedKeys); - }; - - const handleClearSelection = () => { - onSelectChange([]); - setCheckAll(false); - setIndeterminate(false); - }; - - useEffect(() => { - updateCheckStatus(selectedKeys); - }, [selectedKeys, options]); - - const renderRight = () => { - return ( - -
    - ({selectedKeys.length}) selected - -
    - - selectedKeys.includes(item.key) - )} - onUnselect={handleOnUnselect} - /> -
    - ); - }; - - return ( - - -
    - - - - {intl.formatMessage( - { id: 'common.select.count' }, - { count: selectedKeys.length } - )} - - - - } - size="small" - allowClear - status={'null' as any} - placeholder={searchPlaceholder} - style={{ - width: 300, - height: 32, - borderRadius: 4, - backgroundColor: 'var(--ant-color-bg-container) !important' - }} - onChange={handleSearch} - /> -
    - {showOptions.length > 0 ? ( - - ) : ( - - )} -
    -
    - ); -}; - -export default SelectPanel; diff --git a/src/pages/_components/select-panel/list.tsx b/src/pages/_components/select-panel/list.tsx deleted file mode 100644 index 48a92116..00000000 --- a/src/pages/_components/select-panel/list.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { OverlayScroller } from '@/components/overlay-scroller'; -import { Checkbox } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; -import AutoTooltip from '../../../components/auto-tooltip'; - -interface ListProps { - maxHeight?: number; - dataList: Array<{ key: string; title: string }>; - selectedKeys: string[]; - renderTitle?: (item: { key: string; title: string }) => React.ReactNode; - onSelectChange: (selectedKeys: string[]) => void; -} - -const UL = styled.ul` - list-style: none; - margin: 0; - padding: 0; -`; - -const LI = styled.li<{ selected: boolean }>` - display: flex; - align-items: center; - padding: 5px 12px; - cursor: pointer; - border-radius: 2px; - gap: 8px; - &:hover { - background-color: var(--ant-control-item-bg-hover); - } -`; - -const List: React.FC = ({ - maxHeight, - dataList, - selectedKeys, - onSelectChange, - renderTitle -}) => { - const handleClickItem = (item: { key: string; title: string }) => { - const itemKey = item.key; - const newSelectedKeys = selectedKeys.includes(itemKey) - ? selectedKeys.filter((key) => key !== itemKey) - : [...selectedKeys, itemKey]; - onSelectChange(newSelectedKeys); - }; - - return ( - -
      - {dataList.map((item) => ( -
    • handleClickItem(item)} - > - - {renderTitle ? ( - renderTitle(item) - ) : ( - {item.title} - )} -
    • - ))} -
    -
    - ); -}; - -export default List; diff --git a/src/pages/_components/select-panel/selected-list.tsx b/src/pages/_components/select-panel/selected-list.tsx deleted file mode 100644 index 2830fcb4..00000000 --- a/src/pages/_components/select-panel/selected-list.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import { OverlayScroller } from '@/components/overlay-scroller'; -import { Tag } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -const TagInner = styled(Tag)` - border-radius: 12px; - margin: 0; -`; - -const Content = styled.div` - display: flex; - flex-wrap: wrap; - gap: 8px; - padding: 8px 0; -`; - -interface SelectedProps { - maxHeight?: number; - selectedList: { key: string; title: string }[]; - onUnselect: ( - key: string, - newSelectedKeys: { key: string; title: string }[] - ) => void; -} - -const SelectedList: React.FC = ({ - maxHeight, - selectedList, - onUnselect -}) => { - const handleOnUnselect = (key: string) => { - const newSelectedKeys = selectedList.filter((item) => item.key !== key); - onUnselect(key, newSelectedKeys); - }; - - return ( - - - {selectedList.map((item) => ( - { - e.preventDefault(); - handleOnUnselect(item.key); - }} - closable - > - {item.title} - - ))} - - - ); -}; - -export default SelectedList; diff --git a/src/pages/_components/terminal-tabs/tabs.tsx b/src/pages/_components/terminal-tabs/tabs.tsx index d823d88c..0c3dc6a6 100644 --- a/src/pages/_components/terminal-tabs/tabs.tsx +++ b/src/pages/_components/terminal-tabs/tabs.tsx @@ -1,5 +1,5 @@ -import XTerminal from '@/components/x-terminal'; import { CloseOutlined } from '@ant-design/icons'; +import { XTerminal } from '@gpustack/core-ui'; import { Button, Tabs } from 'antd'; import { throttle } from 'lodash'; import React, { useEffect, useMemo, useState } from 'react'; diff --git a/src/pages/_components/yaml-editor/editor.tsx b/src/pages/_components/yaml-editor/editor.tsx index a4889240..28860747 100644 --- a/src/pages/_components/yaml-editor/editor.tsx +++ b/src/pages/_components/yaml-editor/editor.tsx @@ -1,5 +1,5 @@ -import EditorWrap from '@/components/editor-wrap'; import { LoadingOutlined } from '@ant-design/icons'; +import { EditorWrap } from '@gpustack/core-ui'; import Editor, { loader } from '@monaco-editor/react'; import * as monaco from 'monaco-editor'; import { yamlDefaults } from 'monaco-yaml'; diff --git a/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx b/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx index 6a805c45..877eaaf7 100644 --- a/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx +++ b/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx @@ -1,8 +1,8 @@ import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; import useAppUtils from '@/hooks/use-app-utils'; -import SelectPanel from '@/pages/_components/select-panel'; import { queryMyModels } from '@/pages/llmodels/apis'; +import { SelectPanel } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Checkbox, Divider, Form, Radio } from 'antd'; import { useEffect, useState } from 'react'; diff --git a/src/pages/api-keys/components/add-apikey-modal/form.tsx b/src/pages/api-keys/components/add-apikey-modal/form.tsx index b6c3a05f..e98305f0 100644 --- a/src/pages/api-keys/components/add-apikey-modal/form.tsx +++ b/src/pages/api-keys/components/add-apikey-modal/form.tsx @@ -1,8 +1,10 @@ -import Password from '@/components/seal-form/password'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; +import { + Input as CInput, + Password, + Select as SealSelect +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React from 'react'; @@ -34,12 +36,12 @@ const APIKeyForm: React.FC<{ } ]} > - + > @@ -66,10 +68,10 @@ const APIKeyForm: React.FC<{ > name="description" rules={[{ required: false }]}> - + > {action === PageAction.CREATE && ( <> diff --git a/src/pages/api-keys/components/add-apikey-modal/index.tsx b/src/pages/api-keys/components/add-apikey-modal/index.tsx index 06806198..c57629af 100644 --- a/src/pages/api-keys/components/add-apikey-modal/index.tsx +++ b/src/pages/api-keys/components/add-apikey-modal/index.tsx @@ -1,11 +1,13 @@ -import AlertBlockInfo from '@/components/alert-info/block'; -import CopyButton from '@/components/copy-button'; -import ModalFooter from '@/components/modal-footer'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; -import SealInput from '@/components/seal-form/seal-input'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; +import { + AlertBlockInfo, + Input as CInput, + ColumnWrapper, + CopyButton, + GSDrawer, + ModalFooter +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form, Tag } from 'antd'; import dayjs from 'dayjs'; @@ -296,7 +298,7 @@ const AddModal: React.FC = ({ {intl.formatMessage({ id: 'apikeys.table.save.tips' })} - = ({ type="text" > } - > + > )} diff --git a/src/pages/api-keys/hooks/use-keys-columns.tsx b/src/pages/api-keys/hooks/use-keys-columns.tsx index a11dca29..fa38c5eb 100644 --- a/src/pages/api-keys/hooks/use-keys-columns.tsx +++ b/src/pages/api-keys/hooks/use-keys-columns.tsx @@ -1,15 +1,13 @@ // columns.ts -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; -import icons from '@/components/icon-font/icons'; import { tableSorter } from '@/config/settings'; +import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; import { useIntl } from '@umijs/max'; import { Tag } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import dayjs from 'dayjs'; import { useMemo } from 'react'; import { ListItem } from '../config/types'; - interface ColumnsHookProps { handleSelect: (val: string, record: ListItem) => void; sortOrder: string[]; diff --git a/src/pages/api-keys/index.tsx b/src/pages/api-keys/index.tsx index 25078e55..a6304f1b 100644 --- a/src/pages/api-keys/index.tsx +++ b/src/pages/api-keys/index.tsx @@ -1,12 +1,10 @@ -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import { PaginationKey } from '@/config/settings'; import type { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; import useQueryUserList from '@/pages/users/services/use-query-user-list'; import { useModel } from '@@/plugin-model'; +import { DeleteModal, FilterBar, IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import useMemoizedFn from 'ahooks/lib/useMemoizedFn'; import { ConfigProvider, Table } from 'antd'; @@ -191,7 +189,7 @@ const APIKeys: React.FC = () => { rowKey="id" onChange={handleTableChange} pagination={{ - size: 'default', + size: 'middle', showSizeChanger: true, pageSize: queryParams.perPage, current: queryParams.page, diff --git a/src/pages/backends/community/add-community-modal.tsx b/src/pages/backends/community/add-community-modal.tsx index e7f397fe..a93f19f4 100644 --- a/src/pages/backends/community/add-community-modal.tsx +++ b/src/pages/backends/community/add-community-modal.tsx @@ -1,7 +1,6 @@ import { enabledBackendsAtom } from '@/atoms/backend'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; import Separator from '@/pages/llmodels/components/separator'; +import { ColumnWrapper, GSDrawer } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useAtom } from 'jotai'; import React, { useEffect } from 'react'; diff --git a/src/pages/backends/community/backend-detail.tsx b/src/pages/backends/community/backend-detail.tsx index 23cdec27..6a9ae093 100644 --- a/src/pages/backends/community/backend-detail.tsx +++ b/src/pages/backends/community/backend-detail.tsx @@ -1,13 +1,11 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import FullMarkdown from '@/components/markdown-viewer/full-markdown'; import { BulbOutlined } from '@ant-design/icons'; +import { AutoTooltip, FullMarkdown } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Tag } from 'antd'; import _ from 'lodash'; import React, { useEffect } from 'react'; import styled from 'styled-components'; import { generateIcon } from '../components/backend-card'; - const Title = styled.div` position: sticky; top: 0; diff --git a/src/pages/backends/community/commnity-backends.tsx b/src/pages/backends/community/commnity-backends.tsx index b800e2ae..5b6113aa 100644 --- a/src/pages/backends/community/commnity-backends.tsx +++ b/src/pages/backends/community/commnity-backends.tsx @@ -1,8 +1,7 @@ import { enabledBackendsAtom } from '@/atoms/backend'; -import IconFont from '@/components/icon-font'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; import useTableFetch from '@/hooks/use-table-fetch'; import { SearchOutlined } from '@ant-design/icons'; +import { IconFont, ThemeTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Input, Tooltip } from 'antd'; import { useAtom } from 'jotai'; diff --git a/src/pages/backends/components/add-modal.tsx b/src/pages/backends/components/add-modal.tsx index 0ad11867..bc5881a5 100644 --- a/src/pages/backends/components/add-modal.tsx +++ b/src/pages/backends/components/add-modal.tsx @@ -1,10 +1,12 @@ -import AlertBlockInfo from '@/components/alert-info/block'; -import IconFont from '@/components/icon-font'; -import ModalFooter from '@/components/modal-footer'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; -import SegmentLine from '@/components/segment-line'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; +import { + AlertBlockInfo, + GSDrawer, + IconFont, + ModalFooter, + SegmentLine +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tabs } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/backends/components/backend-card.tsx b/src/pages/backends/components/backend-card.tsx index 96304bbe..8e4e7158 100644 --- a/src/pages/backends/components/backend-card.tsx +++ b/src/pages/backends/components/backend-card.tsx @@ -1,9 +1,11 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import DropDownActions from '@/components/drop-down-actions'; -import IconFont from '@/components/icon-font'; -import TagWrapper from '@/components/tags-wrapper'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; -import Card from '@/components/templates/card'; +import { + AutoTooltip, + DropdownActions, + IconFont, + TagsWrapper, + TemplateCard, + ThemeTag +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Tag } from 'antd'; import _ from 'lodash'; @@ -22,8 +24,7 @@ import { TagColorMap } from '../config'; import { ListItem } from '../config/types'; - -const StyledCard = styled(Card)` +const StyledCard = styled(TemplateCard)` &:hover { .operations { background-color: var(--ant-color-fill-tertiary); @@ -231,11 +232,11 @@ const BackendCard: React.FC = ({ {intl.formatMessage({ id: 'backend.availableFrameworks' })}:{' '} - + > ); }; @@ -279,7 +280,7 @@ const BackendCard: React.FC = ({ actionsRenderer(data) ) : ( - = ({ size="small" type="text" > - + ); }; diff --git a/src/pages/backends/components/backend-list.tsx b/src/pages/backends/components/backend-list.tsx index 2514f247..aa326ad2 100644 --- a/src/pages/backends/components/backend-list.tsx +++ b/src/pages/backends/components/backend-list.tsx @@ -1,7 +1,9 @@ -import ResizeContainer from '@/components/resize-container'; -import CardSkeleton from '@/components/templates/card-skelton'; -import InfiniteScroller from '@/pages/_components/infinite-scroller'; -import { useScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context'; +import { + InfiniteScroller, + ResizeContainer, + TemplateCardSkeleton +} from '@gpustack/core-ui'; +import { useScrollerContext } from '@gpustack/core-ui/lib/components/infinite-scroller/use-scroller-context'; import { Spin } from 'antd'; import React from 'react'; import backendListCss from '../styles/backend-list.less'; @@ -38,7 +40,7 @@ const ListSkeleton: React.FC<{ > {isFirst && (
    - + >
    )} diff --git a/src/pages/backends/components/import-yaml.tsx b/src/pages/backends/components/import-yaml.tsx index 627a288b..0ae373f3 100644 --- a/src/pages/backends/components/import-yaml.tsx +++ b/src/pages/backends/components/import-yaml.tsx @@ -1,6 +1,6 @@ import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import YamlEditor from '@/pages/_components/yaml-editor'; +import { YamlEditor } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import React, { forwardRef, diff --git a/src/pages/backends/components/version-info-modal.tsx b/src/pages/backends/components/version-info-modal.tsx index b0604fbc..8969fd11 100644 --- a/src/pages/backends/components/version-info-modal.tsx +++ b/src/pages/backends/components/version-info-modal.tsx @@ -1,5 +1,5 @@ -import ScrollerModal from '@/components/scroller-modal'; import { PlusOutlined } from '@ant-design/icons'; +import { ScrollerModal } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/backends/config/index.ts b/src/pages/backends/config/index.ts index 3c68d8f5..0c07d3f9 100644 --- a/src/pages/backends/config/index.ts +++ b/src/pages/backends/config/index.ts @@ -2,12 +2,12 @@ import MindIELogo from '@/assets/logo/ascend.png'; import SGLangLogo from '@/assets/logo/sglang.png'; import vLLMLogo from '@/assets/logo/vllm.png'; import VoxBoxLogo from '@/assets/logo/voxbox.png'; -import icons from '@/components/icon-font/icons'; import { backendOptionsMap } from '@/pages/llmodels/constants/backend-parameters'; import { GPUDriverMap, ManufacturerMap } from '@/pages/resources/config/gpu-driver'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; import jsYaml from 'js-yaml'; import { trim } from 'lodash'; diff --git a/src/pages/backends/forms/basic.tsx b/src/pages/backends/forms/basic.tsx index db890d2b..55f83e44 100644 --- a/src/pages/backends/forms/basic.tsx +++ b/src/pages/backends/forms/basic.tsx @@ -1,9 +1,11 @@ -import LabelSelector from '@/components/label-selector'; -import ListInput from '@/components/list-input'; -import SealInput from '@/components/seal-form/seal-input'; -import SealTextArea from '@/components/seal-form/seal-textarea'; import { PageAction } from '@/config'; import useAppUtils from '@/hooks/use-app-utils'; +import { + Input as CInput, + LabelSelector, + ListInput, + Textarea as SealTextArea +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import { useEffect } from 'react'; @@ -39,7 +41,7 @@ const BasicForm = () => { } ]} > - { disabled={action === PageAction.EDIT} label={intl.formatMessage({ id: 'common.table.name' })} required - > + > hidden name="backend_source"> - + {backendSource !== BackendSourceValueMap.BUILTIN && ( <> @@ -58,11 +60,11 @@ const BasicForm = () => { name="health_check_path" rules={[{ required: false }]} > - + > { name="description" rules={[{ required: false }]}> - + > ); diff --git a/src/pages/backends/forms/version-info.tsx b/src/pages/backends/forms/version-info.tsx index a896e163..acaf8a56 100644 --- a/src/pages/backends/forms/version-info.tsx +++ b/src/pages/backends/forms/version-info.tsx @@ -1,7 +1,9 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import CopyButton from '@/components/copy-button'; -import BaseSelect from '@/components/seal-form/base/select'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; +import { + AutoTooltip, + BaseSelect, + CopyButton, + ThemeTag +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Empty, Typography } from 'antd'; import { useState } from 'react'; @@ -14,7 +16,6 @@ import { TagColorMap } from '../config'; import { VersionListItem } from '../config/types'; - const ItemWrapper = styled.div` display: flex; flex-direction: column; diff --git a/src/pages/backends/forms/versions-config.tsx b/src/pages/backends/forms/versions-config.tsx index 646d6966..2fafa591 100644 --- a/src/pages/backends/forms/versions-config.tsx +++ b/src/pages/backends/forms/versions-config.tsx @@ -1,12 +1,14 @@ -import CollapsibleContainer from '@/components/collapse-container'; -import LabelSelector from '@/components/label-selector'; -import BaseSelect from '@/components/seal-form/base/select'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; -import SealTextArea from '@/components/seal-form/seal-textarea'; import { PageActionType } from '@/config/types'; import useAppUtils from '@/hooks/use-app-utils'; import { MinusOutlined, PlusOutlined } from '@ant-design/icons'; +import { + BaseSelect, + Input as CInput, + CollapseContainer, + LabelSelector, + Select as SealSelect, + Textarea as SealTextArea +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Form, Tag } from 'antd'; import React, { useEffect, useMemo } from 'react'; @@ -14,7 +16,6 @@ import styled from 'styled-components'; import { BackendSourceValueMap, frameworks } from '../config'; import { useFormContext } from '../config/form-context'; import { ListItem } from '../config/types'; - // version must be endwith '-custom' const Box = styled.div` @@ -263,7 +264,7 @@ const VersionsForm: React.FC = ({ border: '1px solid var(--ant-color-split)' }} > - = ({ )} } - onToggle={(open) => onToggle(open, name)} + onToggle={(open: boolean) => onToggle(open, name)} deleteBtn={false} right={
    @@ -328,13 +329,13 @@ const VersionsForm: React.FC = ({ } ]} > - + > = ({ } ]} > - = ({ { content: 'vllm/vllm-openai:v0.12.0' } )} label={intl.formatMessage({ id: 'backend.imageName' })} - > + > = ({ /> - = ({ label={intl.formatMessage({ id: 'backend.replaceEntrypoint' })} - > + > = ({ } > - +
    )); }} diff --git a/src/pages/backends/hooks/use-create-backend.tsx b/src/pages/backends/hooks/use-create-backend.tsx index ff1a2a97..8084015f 100644 --- a/src/pages/backends/hooks/use-create-backend.tsx +++ b/src/pages/backends/hooks/use-create-backend.tsx @@ -1,7 +1,7 @@ -import IconFont from '@/components/icon-font'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; import useBodyScroll from '@/hooks/use-body-scroll'; +import { IconFont } from '@gpustack/core-ui'; import { ListItem } from '../config/types'; import useCommunityBackend from './use-community-backend'; import useCustomBackend from './use-custom-backend'; diff --git a/src/pages/backends/index.tsx b/src/pages/backends/index.tsx index 91f28a3b..76b26c81 100644 --- a/src/pages/backends/index.tsx +++ b/src/pages/backends/index.tsx @@ -1,8 +1,6 @@ -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import useTableFetch from '@/hooks/use-table-fetch'; +import { DeleteModal, FilterBar, IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import useMemoizedFn from 'ahooks/lib/useMemoizedFn'; import _ from 'lodash'; diff --git a/src/pages/benchmark/components/add-benchmark-modal.tsx b/src/pages/benchmark/components/add-benchmark-modal.tsx index e46f4ec3..91685666 100644 --- a/src/pages/benchmark/components/add-benchmark-modal.tsx +++ b/src/pages/benchmark/components/add-benchmark-modal.tsx @@ -1,5 +1,5 @@ import { PageActionType } from '@/config/types'; -import FormDrawer from '@/pages/_components/form-drawer'; +import { FormDrawer } from '@gpustack/core-ui'; import React, { useRef } from 'react'; import { FormData, BenchmarkListItem as ListItem } from '../config/types'; diff --git a/src/pages/benchmark/components/detail-content.tsx b/src/pages/benchmark/components/detail-content.tsx index 2c1ca27f..88b64788 100644 --- a/src/pages/benchmark/components/detail-content.tsx +++ b/src/pages/benchmark/components/detail-content.tsx @@ -1,4 +1,4 @@ -import IconFont from '@/components/icon-font'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl, useSearchParams } from '@umijs/max'; import { Tabs, TabsProps } from 'antd'; import React, { useState } from 'react'; diff --git a/src/pages/benchmark/components/detail-modal.tsx b/src/pages/benchmark/components/detail-modal.tsx index 036d9825..cff4a023 100644 --- a/src/pages/benchmark/components/detail-modal.tsx +++ b/src/pages/benchmark/components/detail-modal.tsx @@ -1,4 +1,4 @@ -import FormDrawer from '@/pages/_components/form-drawer'; +import { FormDrawer } from '@gpustack/core-ui'; import { BenchmarkListItem } from '../config/types'; import DetailContent from './detail-content'; diff --git a/src/pages/benchmark/components/environment/index.tsx b/src/pages/benchmark/components/environment/index.tsx index 1acee7e0..52a5dbbc 100644 --- a/src/pages/benchmark/components/environment/index.tsx +++ b/src/pages/benchmark/components/environment/index.tsx @@ -1,7 +1,9 @@ -import RowChildren from '@/components/seal-table/components/row-children'; -import SealTable from '@/components/seal-table/index'; -import TableContext from '@/components/seal-table/table-context'; import useExpandedRowKeys from '@/hooks/use-expanded-row-keys'; +import { + RowChildren, + Table as SealTable, + TableProvider +} from '@gpustack/core-ui'; import useMemoizedFn from 'ahooks/lib/useMemoizedFn'; import { Col, Row } from 'antd'; import _ from 'lodash'; @@ -175,7 +177,7 @@ const Environment: React.FC = () => { return ( - { columns={workerColumns} expandable={true} > - + ); }; diff --git a/src/pages/benchmark/components/environment/use-gpu-columns.tsx b/src/pages/benchmark/components/environment/use-gpu-columns.tsx index 301b287f..aefdc35c 100644 --- a/src/pages/benchmark/components/environment/use-gpu-columns.tsx +++ b/src/pages/benchmark/components/environment/use-gpu-columns.tsx @@ -1,7 +1,6 @@ -import AutoTooltip from '@/components/auto-tooltip'; import { convertFileSize } from '@/utils'; +import { AutoTooltip } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; - export default function useGPUColumns(): { title: string; dataIndex: string; diff --git a/src/pages/benchmark/components/environment/use-worker-columns.tsx b/src/pages/benchmark/components/environment/use-worker-columns.tsx index c8e1be4f..84f95375 100644 --- a/src/pages/benchmark/components/environment/use-worker-columns.tsx +++ b/src/pages/benchmark/components/environment/use-worker-columns.tsx @@ -1,8 +1,7 @@ -import AutoTooltip from '@/components/auto-tooltip'; import { convertFileSize } from '@/utils'; +import { AutoTooltip } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tag } from 'antd'; - export default function useWorkerColumns(): { title: string; dataIndex: string; diff --git a/src/pages/benchmark/components/left-actions.tsx b/src/pages/benchmark/components/left-actions.tsx index 2bff3045..40889baa 100644 --- a/src/pages/benchmark/components/left-actions.tsx +++ b/src/pages/benchmark/components/left-actions.tsx @@ -1,6 +1,6 @@ -import { FiltersButton } from '@/components/page-tools'; import { modelCategoriesMap } from '@/pages/llmodels/config'; import { SearchOutlined, SyncOutlined } from '@ant-design/icons'; +import { FiltersButton } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Input, Space } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/benchmark/components/logs/index.tsx b/src/pages/benchmark/components/logs/index.tsx index 32acab4d..0c643673 100644 --- a/src/pages/benchmark/components/logs/index.tsx +++ b/src/pages/benchmark/components/logs/index.tsx @@ -1,4 +1,4 @@ -import LogsViewer from '@/components/logs-viewer/virtual-log-list'; +import { LogsViewer } from '@gpustack/core-ui'; import React, { useRef } from 'react'; import { BENCHMARKS_API } from '../../apis'; import { useDetailContext } from '../../config/detail-context'; diff --git a/src/pages/benchmark/components/right-actions.tsx b/src/pages/benchmark/components/right-actions.tsx index 7da00fc5..cc875c89 100644 --- a/src/pages/benchmark/components/right-actions.tsx +++ b/src/pages/benchmark/components/right-actions.tsx @@ -1,6 +1,5 @@ -import DropdownButtons from '@/components/drop-down-buttons'; -import IconFont from '@/components/icon-font'; import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; +import { DropdownButtons, IconFont } from '@gpustack/core-ui'; import { Button, Space } from 'antd'; import React from 'react'; diff --git a/src/pages/benchmark/components/row-actions.tsx b/src/pages/benchmark/components/row-actions.tsx index 41cbd966..0c6b5cb2 100644 --- a/src/pages/benchmark/components/row-actions.tsx +++ b/src/pages/benchmark/components/row-actions.tsx @@ -1,8 +1,7 @@ -import DropdownButtons from '@/components/drop-down-buttons'; -import IconFont from '@/components/icon-font'; -import icons from '@/components/icon-font/icons'; import useDownloadLogs from '@/hooks/use-download-logs'; import { DownloadOutlined } from '@ant-design/icons'; +import { DropdownButtons, IconFont } from '@gpustack/core-ui'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; import { BENCHMARKS_API } from '../apis'; import { BenchmarkStatusValueMap } from '../config'; import { BenchmarkListItem as ListItem } from '../config/types'; diff --git a/src/pages/benchmark/components/summary/instance.tsx b/src/pages/benchmark/components/summary/instance.tsx index c941b4ff..de9cd86b 100644 --- a/src/pages/benchmark/components/summary/instance.tsx +++ b/src/pages/benchmark/components/summary/instance.tsx @@ -1,9 +1,8 @@ -import AutoTooltip from '@/components/auto-tooltip'; +import { AutoTooltip } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Descriptions, Flex, Tag } from 'antd'; import React, { useMemo } from 'react'; import { useDetailContext } from '../../config/detail-context'; - const Instance: React.FC = () => { const intl = useIntl(); const { detailData } = useDetailContext(); diff --git a/src/pages/benchmark/components/summary/section.tsx b/src/pages/benchmark/components/summary/section.tsx index 2e2462fb..052455c0 100644 --- a/src/pages/benchmark/components/summary/section.tsx +++ b/src/pages/benchmark/components/summary/section.tsx @@ -1,5 +1,4 @@ -import HeadlessCollapse from '@/components/collapse-container/headless-collapse'; -import IconFont from '@/components/icon-font'; +import { HeadlessCollapse, IconFont } from '@gpustack/core-ui'; import { useState } from 'react'; import styled from 'styled-components'; diff --git a/src/pages/benchmark/components/view-logs-modal.tsx b/src/pages/benchmark/components/view-logs-modal.tsx index 76e2bcb8..958296be 100644 --- a/src/pages/benchmark/components/view-logs-modal.tsx +++ b/src/pages/benchmark/components/view-logs-modal.tsx @@ -1,4 +1,4 @@ -import LogsViewer from '@/components/logs-viewer/virtual-log-list'; +import { LogsViewer } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Modal } from 'antd'; import React, { useCallback, useEffect } from 'react'; diff --git a/src/pages/benchmark/details.tsx b/src/pages/benchmark/details.tsx index 414bdce4..c6f437c2 100644 --- a/src/pages/benchmark/details.tsx +++ b/src/pages/benchmark/details.tsx @@ -1,5 +1,4 @@ -import DeleteModal from '@/components/delete-modal'; -import BaseSelect from '@/components/seal-form/base/select'; +import { BaseSelect, DeleteModal } from '@gpustack/core-ui'; import { useIntl, useNavigate, useSearchParams } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import React, { useEffect, useRef } from 'react'; @@ -18,7 +17,6 @@ import useQueryBenchmarkList from './services/use-query-benchmarks'; import useQueryDetail from './services/use-query-detail'; import useQueryProfiles from './services/use-query-profiles'; import useStopBenchmark from './services/use-stop-benchmark'; - const Details: React.FC = () => { const modalRef = useRef(null); const navigate = useNavigate(); diff --git a/src/pages/benchmark/filters/index.tsx b/src/pages/benchmark/filters/index.tsx index e38fa043..054fc23d 100644 --- a/src/pages/benchmark/filters/index.tsx +++ b/src/pages/benchmark/filters/index.tsx @@ -1,13 +1,11 @@ -import BaseSelect from '@/components/seal-form/base/select'; -import FilterForm from '@/pages/_components/filter-form'; import { modelCategoriesMap } from '@/pages/llmodels/config'; import { SearchOutlined } from '@ant-design/icons'; +import { BaseSelect, FilterForm } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form, Input } from 'antd'; import { forwardRef, useImperativeHandle, useRef } from 'react'; import styled from 'styled-components'; import { profileOptions } from '../config'; - const Content = styled.div` display: flex; flex-direction: column; diff --git a/src/pages/benchmark/forms/basic.tsx b/src/pages/benchmark/forms/basic.tsx index e55c0d14..402aab77 100644 --- a/src/pages/benchmark/forms/basic.tsx +++ b/src/pages/benchmark/forms/basic.tsx @@ -1,9 +1,8 @@ -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; import { modelNameReg, PageAction } from '@/config'; import useAppUtils from '@/hooks/use-app-utils'; import { ClusterStatusValueMap } from '@/pages/cluster-management/config'; import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-benchmark'; +import { Input as CInput, Select as SealSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React, { useEffect } from 'react'; @@ -60,10 +59,10 @@ const BasicForm: React.FC = () => { } ]} > - + > name="cluster_id" @@ -82,22 +81,22 @@ const BasicForm: React.FC = () => { > name="model_name" hidden={true}> - + name="model_id" hidden={true}> - + name="model_instance_name" hidden={true}> - + name="description"> - + > ); diff --git a/src/pages/benchmark/forms/dataset.tsx b/src/pages/benchmark/forms/dataset.tsx index 2b0e11bc..92ca0e2e 100644 --- a/src/pages/benchmark/forms/dataset.tsx +++ b/src/pages/benchmark/forms/dataset.tsx @@ -1,7 +1,6 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import useAppUtils from '@/hooks/use-app-utils'; +import { AutoTooltip, Select as SealSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form, Select } from 'antd'; import _ from 'lodash'; @@ -10,7 +9,6 @@ import { ProfileValueMap } from '../config'; import { useFormContext } from '../config/form-context'; import { FormData } from '../config/types'; import RandomSettingsForm from './random-settings'; - const DatasetForm: React.FC = () => { const intl = useIntl(); const form = Form.useFormInstance(); diff --git a/src/pages/benchmark/forms/index.tsx b/src/pages/benchmark/forms/index.tsx index 2e373374..2b808c6b 100644 --- a/src/pages/benchmark/forms/index.tsx +++ b/src/pages/benchmark/forms/index.tsx @@ -1,9 +1,7 @@ -import IconFont from '@/components/icon-font'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import CollapsePanel from '@/pages/_components/collapse-panel'; -import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context'; -import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs'; +import { CollapsePanel, IconFont, ScrollSpyTabs } from '@gpustack/core-ui'; +import { useWrapperContext } from '@gpustack/core-ui/lib/components/column-wrapper/use-wrapper-context'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import { diff --git a/src/pages/benchmark/forms/labels.tsx b/src/pages/benchmark/forms/labels.tsx index 96e28703..cf067bb4 100644 --- a/src/pages/benchmark/forms/labels.tsx +++ b/src/pages/benchmark/forms/labels.tsx @@ -1,4 +1,4 @@ -import LabelSelector from '@/components/label-selector'; +import { LabelSelector } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/benchmark/forms/model-instance.tsx b/src/pages/benchmark/forms/model-instance.tsx index 74d39431..bc2ac427 100644 --- a/src/pages/benchmark/forms/model-instance.tsx +++ b/src/pages/benchmark/forms/model-instance.tsx @@ -1,4 +1,3 @@ -import SealCascader from '@/components/seal-form/seal-cascader'; import { PageAction } from '@/config'; import useAppUtils from '@/hooks/use-app-utils'; import { @@ -9,6 +8,7 @@ import { import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-benchmark'; import { useQueryModelInstancesList } from '@/pages/llmodels/services/use-query-model-instances'; import { useQueryModelList } from '@/pages/llmodels/services/use-query-model-list'; +import { Cascader as SealCascader } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form, Tooltip } from 'antd'; import React, { useEffect } from 'react'; diff --git a/src/pages/benchmark/forms/random-settings.tsx b/src/pages/benchmark/forms/random-settings.tsx index 578b42b3..bd8a3afa 100644 --- a/src/pages/benchmark/forms/random-settings.tsx +++ b/src/pages/benchmark/forms/random-settings.tsx @@ -1,7 +1,9 @@ -import SealInputNumber from '@/components/seal-form/input-number'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import useAppUtils from '@/hooks/use-app-utils'; +import { + InputNumber as CInputNumber, + Select as SealSelect +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React, { useMemo } from 'react'; @@ -62,14 +64,14 @@ const RandomSettingsForm: React.FC<{ } ]} > - + > name="dataset_output_tokens" @@ -83,24 +85,24 @@ const RandomSettingsForm: React.FC<{ } ]} > - + > name="dataset_seed" getValueProps={(value) => ({ value: value || null })} > - + > )} @@ -114,11 +116,11 @@ const RandomSettingsForm: React.FC<{ } ]} > - + > name="total_requests" @@ -129,12 +131,12 @@ const RandomSettingsForm: React.FC<{ } ]} > - + > ); diff --git a/src/pages/benchmark/hooks/use-benchmark-columns.tsx b/src/pages/benchmark/hooks/use-benchmark-columns.tsx index 2354dcb9..f7647f56 100644 --- a/src/pages/benchmark/hooks/use-benchmark-columns.tsx +++ b/src/pages/benchmark/hooks/use-benchmark-columns.tsx @@ -1,13 +1,12 @@ // columns.ts -import AutoTooltip from '@/components/auto-tooltip'; import { tableSorter } from '@/config/settings'; +import { AutoTooltip } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Typography } from 'antd'; import { ColumnsType } from 'antd/es/table'; import { useMemo } from 'react'; import RowActions from '../components/row-actions'; import { BenchmarkListItem as ListItem } from '../config/types'; - const useBenchmarkColumns = (params: { sortOrder: string[]; columns: ColumnsType; diff --git a/src/pages/benchmark/hooks/use-column-settings.tsx b/src/pages/benchmark/hooks/use-column-settings.tsx index e16e950f..bd5b9c6f 100644 --- a/src/pages/benchmark/hooks/use-column-settings.tsx +++ b/src/pages/benchmark/hooks/use-column-settings.tsx @@ -1,8 +1,10 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import InfoColumn from '@/components/simple-table/info-column'; -import StatusTag from '@/components/status-tag'; import { tableSorter } from '@/config/settings'; -import ColumnSettings from '@/pages/_components/column-settings'; +import { + AutoTooltip, + ColumnSettings, + InfoColumn, + StatusTag +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Typography } from 'antd'; import dayjs from 'dayjs'; @@ -14,7 +16,6 @@ import { BenchmarkStatusValueMap } from '../config'; import { BenchmarkListItem as ListItem } from '../config/types'; - // sort by this order const allFields = [ 'cluster_id', diff --git a/src/pages/benchmark/index.tsx b/src/pages/benchmark/index.tsx index be86fa1e..08daddf5 100644 --- a/src/pages/benchmark/index.tsx +++ b/src/pages/benchmark/index.tsx @@ -1,11 +1,9 @@ -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings'; import useTableFetch from '@/hooks/use-table-fetch'; import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-benchmark'; import { useQueryModelList } from '@/pages/llmodels/services/use-query-model-list'; +import { DeleteModal, FilterBar, IconFont } from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { useMemoizedFn, useToggle } from 'ahooks'; import { ConfigProvider, Table, message } from 'antd'; diff --git a/src/pages/cluster-management/cluster-create.tsx b/src/pages/cluster-management/cluster-create.tsx index 91c56d84..a84191af 100644 --- a/src/pages/cluster-management/cluster-create.tsx +++ b/src/pages/cluster-management/cluster-create.tsx @@ -1,7 +1,7 @@ import { systemConfigAtom } from '@/atoms/system'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; +import { ColumnWrapper } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useAtom } from 'jotai'; import _ from 'lodash'; diff --git a/src/pages/cluster-management/cluster-detail.tsx b/src/pages/cluster-management/cluster-detail.tsx index 777ac896..f6df61b2 100644 --- a/src/pages/cluster-management/cluster-detail.tsx +++ b/src/pages/cluster-management/cluster-detail.tsx @@ -1,8 +1,8 @@ import { clusterDetailAtom } from '@/atoms/clusters'; -import IconFont from '@/components/icon-font'; import Deployments from '@/pages/llmodels/deployments'; import GPUList from '@/pages/resources/components/gpus'; import WorkerList from '@/pages/resources/components/workers'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl, useNavigate, useSearchParams } from '@umijs/max'; import { Tabs } from 'antd'; import { useAtomValue } from 'jotai'; diff --git a/src/pages/cluster-management/cluster-modal.tsx b/src/pages/cluster-management/cluster-modal.tsx index 94148c31..5a7b11d2 100644 --- a/src/pages/cluster-management/cluster-modal.tsx +++ b/src/pages/cluster-management/cluster-modal.tsx @@ -1,5 +1,5 @@ -import GSDrawer from '@/components/scroller-modal/gs-drawer'; import { PageAction } from '@/config'; +import { GSDrawer } from '@gpustack/core-ui'; import React from 'react'; import ClusterCreate from './cluster-create'; diff --git a/src/pages/cluster-management/clusters.tsx b/src/pages/cluster-management/clusters.tsx index 107e57f2..7edca203 100644 --- a/src/pages/cluster-management/clusters.tsx +++ b/src/pages/cluster-management/clusters.tsx @@ -1,16 +1,18 @@ import { clusterSessionAtom, expandKeysAtom } from '@/atoms/clusters'; -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; -import SealTable from '@/components/seal-table'; -import TableContext from '@/components/seal-table/table-context'; -import { TableOrder } from '@/components/seal-table/types'; import { PageAction } from '@/config'; import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings'; import type { PageActionType } from '@/config/types'; import useExpandedRowKeys from '@/hooks/use-expanded-row-keys'; import useTableFetch from '@/hooks/use-table-fetch'; import useWatchList from '@/hooks/use-watch-list'; +import { + DeleteModal, + FilterBar, + IconFont, + Table as SealTable, + TableProvider +} from '@gpustack/core-ui'; +import { TableOrder } from '@gpustack/core-ui/lib/components/table/types'; import { useIntl, useNavigate } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { message } from 'antd'; @@ -354,7 +356,7 @@ const Clusters: React.FC = () => { > } > - { onChange: handlePageChange }} > - + = ({ } ]} > - + > {provider === ProviderValueMap.DigitalOcean && ( <> @@ -90,7 +89,7 @@ const AddModal: React.FC = ({ } ]} > - = ({ }} > } - > + > )} name="description" rules={[{ required: false }]}> - + > diff --git a/src/pages/cluster-management/components/add-pool.tsx b/src/pages/cluster-management/components/add-pool.tsx index 06d6d008..9953567c 100644 --- a/src/pages/cluster-management/components/add-pool.tsx +++ b/src/pages/cluster-management/components/add-pool.tsx @@ -1,5 +1,5 @@ import { PageActionType } from '@/config/types'; -import FormDrawer from '@/pages/_components/form-drawer'; +import { FormDrawer } from '@gpustack/core-ui'; import React, { useEffect, useRef } from 'react'; import { ProviderType } from '../config'; import { diff --git a/src/pages/cluster-management/components/add-worker-command.tsx b/src/pages/cluster-management/components/add-worker-command.tsx index 7ed26bee..ce04dad7 100644 --- a/src/pages/cluster-management/components/add-worker-command.tsx +++ b/src/pages/cluster-management/components/add-worker-command.tsx @@ -1,5 +1,5 @@ -import HighlightCode from '@/components/highlight-code'; import { addWorkerGuide } from '@/pages/resources/config'; +import { HighlightCode } from '@gpustack/core-ui'; import React from 'react'; type ViewModalProps = { diff --git a/src/pages/cluster-management/components/add-worker/index.tsx b/src/pages/cluster-management/components/add-worker/index.tsx index 907242a5..fe73747d 100644 --- a/src/pages/cluster-management/components/add-worker/index.tsx +++ b/src/pages/cluster-management/components/add-worker/index.tsx @@ -1,7 +1,6 @@ -import GSDrawer from '@/components/scroller-modal/gs-drawer'; import { createAxiosToken } from '@/hooks/use-chunk-request'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; import useAddWorkerMessage from '@/pages/cluster-management/hooks/use-add-worker-message'; +import { ColumnWrapper, GSDrawer } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Alert } from 'antd'; import React, { useEffect } from 'react'; diff --git a/src/pages/cluster-management/components/add-worker/select-cluster.tsx b/src/pages/cluster-management/components/add-worker/select-cluster.tsx index 708c96b9..cfa94599 100644 --- a/src/pages/cluster-management/components/add-worker/select-cluster.tsx +++ b/src/pages/cluster-management/components/add-worker/select-cluster.tsx @@ -1,4 +1,4 @@ -import BaseSelect from '@/components/seal-form/base/select'; +import { BaseSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Spin, Typography } from 'antd'; import { useEffect, useState } from 'react'; @@ -6,7 +6,6 @@ import { useAddWorkerContext } from './add-worker-context'; import { AddWorkerStepProps, StepNamesMap } from './config'; import { Title } from './constainers'; import StepCollapse from './step-collapse'; - const SelectCluster: React.FC = ({ disabled }) => { const { clusterList, diff --git a/src/pages/cluster-management/components/add-worker/specify-arguments.tsx b/src/pages/cluster-management/components/add-worker/specify-arguments.tsx index 1cfaa448..29076f4c 100644 --- a/src/pages/cluster-management/components/add-worker/specify-arguments.tsx +++ b/src/pages/cluster-management/components/add-worker/specify-arguments.tsx @@ -1,5 +1,5 @@ -import AlertInfoBlock from '@/components/alert-info/block'; import { ExclamationCircleFilled } from '@ant-design/icons'; +import { AlertBlockInfo as AlertInfoBlock } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Input, Switch, Typography } from 'antd'; import React, { useEffect } from 'react'; diff --git a/src/pages/cluster-management/components/add-worker/step-collapse.tsx b/src/pages/cluster-management/components/add-worker/step-collapse.tsx index 3721f3bf..9a0934bb 100644 --- a/src/pages/cluster-management/components/add-worker/step-collapse.tsx +++ b/src/pages/cluster-management/components/add-worker/step-collapse.tsx @@ -1,4 +1,4 @@ -import CollapsibleContainer from '@/components/collapse-container'; +import { CollapseContainer } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button } from 'antd'; import React from 'react'; @@ -72,7 +72,7 @@ const StepCollapse: React.FC = ({ collapseKey?.has(name) ? 'step-collapse-open' : 'step-collapse' } > - = ({ )} - + ); }; diff --git a/src/pages/cluster-management/components/add-worker/vendor-notes.tsx b/src/pages/cluster-management/components/add-worker/vendor-notes.tsx index b37e21b1..b5c3c16f 100644 --- a/src/pages/cluster-management/components/add-worker/vendor-notes.tsx +++ b/src/pages/cluster-management/components/add-worker/vendor-notes.tsx @@ -1,5 +1,5 @@ -import AlertInfoBlock from '@/components/alert-info/block'; import { ExclamationCircleFilled } from '@ant-design/icons'; +import { AlertBlockInfo } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useAddWorkerContext } from './add-worker-context'; import { NotesWrapper } from './constainers'; @@ -15,7 +15,7 @@ const VendorNotes = () => { } as { label: string; notes: string[] }); return ( - { ) : null } - > + > ); }; diff --git a/src/pages/cluster-management/components/check-env-command.tsx b/src/pages/cluster-management/components/check-env-command.tsx index 14d348b0..9dc43929 100644 --- a/src/pages/cluster-management/components/check-env-command.tsx +++ b/src/pages/cluster-management/components/check-env-command.tsx @@ -1,5 +1,5 @@ -import HighlightCode from '@/components/highlight-code'; import { addWorkerGuide } from '@/pages/resources/config'; +import { HighlightCode } from '@gpustack/core-ui'; import React from 'react'; import { ProviderType } from '../config'; diff --git a/src/pages/cluster-management/components/cloud-options.tsx b/src/pages/cluster-management/components/cloud-options.tsx index 1d762865..7d65f475 100644 --- a/src/pages/cluster-management/components/cloud-options.tsx +++ b/src/pages/cluster-management/components/cloud-options.tsx @@ -1,6 +1,7 @@ -import DropDownActions from '@/components/drop-down-actions'; -import ListMap from '@/components/dynamic-form/components/list-map'; -import { FieldSchema } from '@/components/dynamic-form/config/types'; +import { DropdownActions } from '@gpustack/core-ui'; +import ListMap from '@gpustack/core-ui/lib/components/dynamic-form/components/list-map'; +import { FieldSchema } from '@gpustack/core-ui/lib/components/dynamic-form/config/types'; + import { PlusOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; @@ -87,14 +88,14 @@ const CloudOptions: React.FC<{ return ( <> - <DropDownActions menu={menu}> + <DropdownActions menu={menu}> <Button variant="filled" color="default"> <PlusOutlined /> <span> {intl.formatMessage({ id: 'clusters.workerpool.cloudOptions' })} </span> </Button> - </DropDownActions> + </DropdownActions> {fieldList.length > 0 && fieldList.map((field) => ( diff --git a/src/pages/cluster-management/components/cloud-provider-form.tsx b/src/pages/cluster-management/components/cloud-provider-form.tsx index 2c57a7e0..a436ce8e 100644 --- a/src/pages/cluster-management/components/cloud-provider-form.tsx +++ b/src/pages/cluster-management/components/cloud-provider-form.tsx @@ -1,9 +1,8 @@ import { fromClusterCreationAtom } from '@/atoms/clusters'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; import useAppUtils from '@/hooks/use-app-utils'; +import { Input as CInput, Select as SealSelect } from '@gpustack/core-ui'; import { Link, useIntl } from '@umijs/max'; import { Form } from 'antd'; import { useAtom } from 'jotai'; @@ -193,14 +192,14 @@ const CloudProvider: React.FC = (props) => { } ]} > - + > ); diff --git a/src/pages/cluster-management/components/cluster-detail-modal.tsx b/src/pages/cluster-management/components/cluster-detail-modal.tsx index 7a46c976..201ee870 100644 --- a/src/pages/cluster-management/components/cluster-detail-modal.tsx +++ b/src/pages/cluster-management/components/cluster-detail-modal.tsx @@ -1,4 +1,4 @@ -import GSDrawer from '@/components/scroller-modal/gs-drawer'; +import { GSDrawer } from '@gpustack/core-ui'; import React from 'react'; import { ClusterListItem } from '../config/types'; import ClusterDetailContent from './cluster-metrics'; diff --git a/src/pages/cluster-management/components/cluster-form.tsx b/src/pages/cluster-management/components/cluster-form.tsx index ddaf821b..fe954b15 100644 --- a/src/pages/cluster-management/components/cluster-form.tsx +++ b/src/pages/cluster-management/components/cluster-form.tsx @@ -1,9 +1,11 @@ -import SealInput from '@/components/seal-form/seal-input'; -import SealTextArea from '@/components/seal-form/seal-textarea'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import CollapsePanel from '@/pages/_components/collapse-panel'; import { json2Yaml, yaml2Json } from '@/pages/backends/config'; +import { + Input as CInput, + CollapsePanel, + Textarea as SealTextArea +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React, { forwardRef, useEffect, useImperativeHandle } from 'react'; @@ -164,11 +166,11 @@ const ClusterForm: React.FC = forwardRef( } ]} > - + > {provider === ProviderValueMap.DigitalOcean && ( { System Load - + - + - + - + - + - + - + - + diff --git a/src/pages/cluster-management/components/detail/cluster-basic.tsx b/src/pages/cluster-management/components/detail/cluster-basic.tsx index 127ef561..590383f9 100644 --- a/src/pages/cluster-management/components/detail/cluster-basic.tsx +++ b/src/pages/cluster-management/components/detail/cluster-basic.tsx @@ -1,7 +1,5 @@ -import CardWrapper from '@/components/card-wrapper'; -import IconFont from '@/components/icon-font'; -import StatusTag from '@/components/status-tag'; import { StarFilled } from '@ant-design/icons'; +import { CardWrapper, IconFont, StatusTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import type { DescriptionsProps } from 'antd'; import { Descriptions, Tooltip } from 'antd'; diff --git a/src/pages/cluster-management/components/detail/cluster-system-load.tsx b/src/pages/cluster-management/components/detail/cluster-system-load.tsx index c307e138..ba28bcac 100644 --- a/src/pages/cluster-management/components/detail/cluster-system-load.tsx +++ b/src/pages/cluster-management/components/detail/cluster-system-load.tsx @@ -1,4 +1,4 @@ -import CardWrapper from '@/components/card-wrapper'; +import { CardWrapper } from '@gpustack/core-ui'; import { Col, Progress, Row, Tag } from 'antd'; import { round } from 'lodash'; import React, { useEffect } from 'react'; diff --git a/src/pages/cluster-management/components/k8s-provider-form.tsx b/src/pages/cluster-management/components/k8s-provider-form.tsx index 2e56de42..1f5667fe 100644 --- a/src/pages/cluster-management/components/k8s-provider-form.tsx +++ b/src/pages/cluster-management/components/k8s-provider-form.tsx @@ -1,4 +1,4 @@ -import SealSelect from '@/components/seal-form/seal-select'; +import { Select as SealSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React from 'react'; diff --git a/src/pages/cluster-management/components/k8s-volume-mount.tsx b/src/pages/cluster-management/components/k8s-volume-mount.tsx index 0fb62749..1b3d879b 100644 --- a/src/pages/cluster-management/components/k8s-volume-mount.tsx +++ b/src/pages/cluster-management/components/k8s-volume-mount.tsx @@ -1,12 +1,14 @@ -import CollapsibleContainer from '@/components/collapse-container'; -import SealCheckbox from '@/components/seal-form/seal-checkbox'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; -import SealSwitch from '@/components/seal-form/seal-switch'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; import useAppUtils from '@/hooks/use-app-utils'; import { MinusOutlined, PlusOutlined } from '@ant-design/icons'; +import { + Input as CInput, + CollapseContainer, + Checkbox as SealCheckbox, + Select as SealSelect, + Switch as SealSwitch +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Flex, Form } from 'antd'; import React, { useEffect, useState } from 'react'; @@ -157,11 +159,11 @@ const VolumeMountsForm: React.FC<{ action: PageActionType }> = ({ action }) => { borderRadius: 'var(--ant-border-radius-lg)' }} > - onToggle(open, name)} + onToggle={(open: boolean) => onToggle(open, name)} styles={{ body: collapseKey.has(name) ? { padding: 16 } : {}, content: { paddingTop: 0 }, @@ -203,13 +205,12 @@ const VolumeMountsForm: React.FC<{ action: PageActionType }> = ({ action }) => { } ]} > - + > {/* Mount Path */} @@ -232,7 +233,7 @@ const VolumeMountsForm: React.FC<{ action: PageActionType }> = ({ action }) => { } ]} > - = ({ action }) => { label={intl.formatMessage({ id: 'clusters.volume.mountPath' })} - > + > @@ -307,7 +308,7 @@ const VolumeMountsForm: React.FC<{ action: PageActionType }> = ({ action }) => { } ]} > - = ({ action }) => { label={intl.formatMessage({ id: 'clusters.volume.sourceType.hostPath' })} - > + > @@ -364,7 +365,7 @@ const VolumeMountsForm: React.FC<{ action: PageActionType }> = ({ action }) => { } ]} > - = ({ action }) => { } ]} > - = ({ action }) => { )} - + ); }); diff --git a/src/pages/cluster-management/components/pool-form.tsx b/src/pages/cluster-management/components/pool-form.tsx index eec1278f..78e563f4 100644 --- a/src/pages/cluster-management/components/pool-form.tsx +++ b/src/pages/cluster-management/components/pool-form.tsx @@ -2,20 +2,21 @@ import { regionInstanceTypeListAtom, regionOSImageListAtom } from '@/atoms/clusters'; -import CollapsibleContainer, { - CollapsibleContainerProps -} from '@/components/collapse-container'; -import IconFont from '@/components/icon-font'; -import LabelSelector from '@/components/label-selector'; -import AutoComplete from '@/components/seal-form/auto-complete'; -import SealInputNumber from '@/components/seal-form/input-number'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; import useAppUtils from '@/hooks/use-app-utils'; import { CardContainer } from '@/pages/llmodels/components/gpu-card'; import { DeleteOutlined } from '@ant-design/icons'; +import { + AutoComplete, + Input as CInput, + InputNumber as CInputNumber, + CollapseContainer, + IconFont, + LabelSelector, + Select as SealSelect +} from '@gpustack/core-ui'; +import { type CollapseContainerProps } from '@gpustack/core-ui/lib/components/collapse-container'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { Button, Form } from 'antd'; @@ -143,7 +144,7 @@ type AddModalProps = { onFinish: (values: FormData) => void; onDelete?: () => void; showDelete?: boolean; - collapseProps?: CollapsibleContainerProps; + collapseProps?: CollapseContainerProps; }; const InstanceSpecData: React.FC<{ instanceSpec: Record }> = ({ @@ -155,7 +156,7 @@ const InstanceSpecData: React.FC<{ instanceSpec: Record }> = ({ .filter(([key, value]) => value) .map(([key, value]) => ( ))} @@ -305,7 +306,7 @@ const PoolForm: React.FC = forwardRef((props, ref) => { })); return ( - = forwardRef((props, ref) => { } ]} > - + > name="instance_type" @@ -394,12 +395,12 @@ const PoolForm: React.FC = forwardRef((props, ref) => { } ]} > - + > name="batch_size" @@ -413,7 +414,7 @@ const PoolForm: React.FC = forwardRef((props, ref) => { } ]} > - = forwardRef((props, ref) => { id: 'clusters.workerpool.batchSize' })} required - > + > @@ -486,12 +487,12 @@ const PoolForm: React.FC = forwardRef((props, ref) => { name="os_image" hidden> - + - + ); }); diff --git a/src/pages/cluster-management/components/pool-rows.tsx b/src/pages/cluster-management/components/pool-rows.tsx index 3cd44ecf..7ec8379f 100644 --- a/src/pages/cluster-management/components/pool-rows.tsx +++ b/src/pages/cluster-management/components/pool-rows.tsx @@ -1,9 +1,11 @@ -import DeleteModal from '@/components/delete-modal'; -import CellContent from '@/components/seal-table/components/cell-content'; -import RowChildren from '@/components/seal-table/components/row-children'; -import RowContext from '@/components/seal-table/row-context'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; +import { + CellContent, + DeleteModal, + RowChildren, + TableRowProvider +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { Col, message, Row } from 'antd'; @@ -120,7 +122,7 @@ const PoolRows: React.FC = ({ key={data.id} style={{ borderRadius: 'var(--ant-table-header-border-radius)' }} > - + {columns.map((col: Record) => { @@ -139,7 +141,7 @@ const PoolRows: React.FC = ({ })} - + ); })} diff --git a/src/pages/cluster-management/components/provider-catalog.tsx b/src/pages/cluster-management/components/provider-catalog.tsx index 6bfebd3d..474b648e 100644 --- a/src/pages/cluster-management/components/provider-catalog.tsx +++ b/src/pages/cluster-management/components/provider-catalog.tsx @@ -1,5 +1,4 @@ -import IconFont from '@/components/icon-font'; -import Card from '@/components/templates/card'; +import { IconFont, TemplateCard } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tooltip } from 'antd'; import React, { useMemo } from 'react'; @@ -147,7 +146,7 @@ const ProviderCatalog: React.FC = ({ key={action.key} > - onSelect?.(action.key as string, action)} active={current === action.key} @@ -155,7 +154,7 @@ const ProviderCatalog: React.FC = ({ clickable={clickable} header={renderTitle(action)} icon={action.icon} - > + > ))} diff --git a/src/pages/cluster-management/components/register-cluster-inner.tsx b/src/pages/cluster-management/components/register-cluster-inner.tsx index 0f8cf15f..5dc74002 100644 --- a/src/pages/cluster-management/components/register-cluster-inner.tsx +++ b/src/pages/cluster-management/components/register-cluster-inner.tsx @@ -1,4 +1,4 @@ -import HighlightCode from '@/components/highlight-code'; +import { HighlightCode } from '@gpustack/core-ui'; import React, { useMemo } from 'react'; import { generateK8sRegisterCommand } from '../config'; diff --git a/src/pages/cluster-management/components/support-gpus.tsx b/src/pages/cluster-management/components/support-gpus.tsx index 60be47b3..4709e953 100644 --- a/src/pages/cluster-management/components/support-gpus.tsx +++ b/src/pages/cluster-management/components/support-gpus.tsx @@ -7,12 +7,12 @@ import mooreLogo from '@/assets/logo/moore-logo.png'; import nvidiaLogo from '@/assets/logo/nvidia.png'; import theadLogoEN from '@/assets/logo/t-head-en.png'; import theadLogoZH from '@/assets/logo/t-head-zh.png'; -import IconFont from '@/components/icon-font'; import useUserSettings from '@/hooks/use-user-settings'; import { AddWorkerDockerNotes, GPUDriverMap } from '@/pages/resources/config/gpu-driver'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import styled from 'styled-components'; import ProviderCatalog from './provider-catalog'; diff --git a/src/pages/cluster-management/components/trend-chart.tsx b/src/pages/cluster-management/components/trend-chart.tsx index c62428c3..79903605 100644 --- a/src/pages/cluster-management/components/trend-chart.tsx +++ b/src/pages/cluster-management/components/trend-chart.tsx @@ -1,4 +1,4 @@ -import LineChart from '@/components/echarts/line-chart'; +import { LineChart } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import dayjs from 'dayjs'; import _ from 'lodash'; diff --git a/src/pages/cluster-management/components/volumes-config.tsx b/src/pages/cluster-management/components/volumes-config.tsx index 42941399..1e1a62b7 100644 --- a/src/pages/cluster-management/components/volumes-config.tsx +++ b/src/pages/cluster-management/components/volumes-config.tsx @@ -1,6 +1,6 @@ -import ListMap from '@/components/dynamic-form/components/list-map'; -import { statusType } from '@/components/dynamic-form/config/types'; -import useValidateFields from '@/components/dynamic-form/hooks/use-validate-fields'; +import ListMap from '@gpustack/core-ui/lib/components/dynamic-form/components/list-map'; +import { statusType } from '@gpustack/core-ui/lib/components/dynamic-form/config/types'; +import useValidateFields from '@gpustack/core-ui/lib/components/dynamic-form/hooks/use-validate-fields'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React, { forwardRef, useState } from 'react'; diff --git a/src/pages/cluster-management/components/worker-pools.tsx b/src/pages/cluster-management/components/worker-pools.tsx index 94a621f2..79a98d13 100644 --- a/src/pages/cluster-management/components/worker-pools.tsx +++ b/src/pages/cluster-management/components/worker-pools.tsx @@ -1,7 +1,6 @@ -import DeleteModal from '@/components/delete-modal'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import useTableFetch from '@/hooks/use-table-fetch'; +import { DeleteModal, FilterBar } from '@gpustack/core-ui'; import { useIntl, useSearchParams } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { message, Table } from 'antd'; diff --git a/src/pages/cluster-management/config/cloud-options-config.ts b/src/pages/cluster-management/config/cloud-options-config.ts index 608f17b9..4cc73e64 100644 --- a/src/pages/cluster-management/config/cloud-options-config.ts +++ b/src/pages/cluster-management/config/cloud-options-config.ts @@ -1,4 +1,4 @@ -import { FieldSchema } from '@/components/dynamic-form/config/types'; +import { FieldSchema } from '@gpustack/core-ui/lib/components/dynamic-form/config/types'; export const fields = { volumes: { diff --git a/src/pages/cluster-management/config/index.ts b/src/pages/cluster-management/config/index.ts index 6e6c2a2f..47d897f4 100644 --- a/src/pages/cluster-management/config/index.ts +++ b/src/pages/cluster-management/config/index.ts @@ -1,8 +1,8 @@ -import icons from '@/components/icon-font/icons'; import { StatusMaps } from '@/config'; import { GPUSTACK_API_BASE_URL } from '@/config/settings'; import { StatusType } from '@/config/types'; import { GPUsConfigs } from '@/pages/resources/config/gpu-driver'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; export const ClusterStatusValueMap = { Provisioning: 'provisioning', diff --git a/src/pages/cluster-management/config/providers.ts b/src/pages/cluster-management/config/providers.ts index 2fc9a42e..b6ad2272 100644 --- a/src/pages/cluster-management/config/providers.ts +++ b/src/pages/cluster-management/config/providers.ts @@ -1,4 +1,4 @@ -import icons from '@/components/icon-font/icons'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; import React from 'react'; import { ProviderValueMap } from '.'; diff --git a/src/pages/cluster-management/credentials.tsx b/src/pages/cluster-management/credentials.tsx index 4dc474a2..77360b32 100644 --- a/src/pages/cluster-management/credentials.tsx +++ b/src/pages/cluster-management/credentials.tsx @@ -1,11 +1,9 @@ import { clusterSessionAtom, fromClusterCreationAtom } from '@/atoms/clusters'; -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings'; import type { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; +import { DeleteModal, FilterBar, IconFont } from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { ConfigProvider, Table, message } from 'antd'; diff --git a/src/pages/cluster-management/hooks/use-cluster-columns.tsx b/src/pages/cluster-management/hooks/use-cluster-columns.tsx index 1f59c915..34a44b4a 100644 --- a/src/pages/cluster-management/hooks/use-cluster-columns.tsx +++ b/src/pages/cluster-management/hooks/use-cluster-columns.tsx @@ -1,13 +1,15 @@ // columns.ts import { systemConfigAtom } from '@/atoms/system'; -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; -import icons from '@/components/icon-font/icons'; -import { SealColumnProps } from '@/components/seal-table/types'; -import StatusTag from '@/components/status-tag'; import { tableSorter } from '@/config/settings'; -import GrafanaIcon from '@/pages/_components/grafana-icon'; import { StarFilled } from '@ant-design/icons'; +import { + AutoTooltip, + DropdownButtons, + GrafanaIcon, + StatusTag +} from '@gpustack/core-ui'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; +import { ColumnProps as SealColumnProps } from '@gpustack/core-ui/lib/components/table/types'; import { useIntl } from '@umijs/max'; import { Tooltip } from 'antd'; import dayjs from 'dayjs'; @@ -20,7 +22,6 @@ import { ProviderValueMap } from '../config'; import { ClusterListItem } from '../config/types'; - const clusterActionList = [ { key: 'edit', diff --git a/src/pages/cluster-management/hooks/use-credential-columns.tsx b/src/pages/cluster-management/hooks/use-credential-columns.tsx index 0a140f09..94749694 100644 --- a/src/pages/cluster-management/hooks/use-credential-columns.tsx +++ b/src/pages/cluster-management/hooks/use-credential-columns.tsx @@ -1,14 +1,12 @@ // columns.ts -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; import { tableSorter } from '@/config/settings'; +import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { ColumnsType } from 'antd/es/table'; import dayjs from 'dayjs'; import { useMemo } from 'react'; import { ProviderLabelMap, credentialActionList } from '../config'; import { CredentialListItem as ListItem } from '../config/types'; - const useCredentialColumns = ( sortOrder: string[], handleSelect: (val: string, record: ListItem) => void diff --git a/src/pages/cluster-management/hooks/use-pools-columns.tsx b/src/pages/cluster-management/hooks/use-pools-columns.tsx index 6430dddf..0ee0d660 100644 --- a/src/pages/cluster-management/hooks/use-pools-columns.tsx +++ b/src/pages/cluster-management/hooks/use-pools-columns.tsx @@ -1,14 +1,12 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; -import { SealColumnProps } from '@/components/seal-table/types'; import { DeleteOutlined, EditOutlined } from '@ant-design/icons'; +import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui'; +import { ColumnProps } from '@gpustack/core-ui/lib/components/table/types'; import { useIntl } from '@umijs/max'; import dayjs from 'dayjs'; import _ from 'lodash'; import { useMemo } from 'react'; import { RenderOption } from '../components/pool-form'; import { NodePoolListItem as ListItem } from '../config/types'; - const actionItems = [ { key: 'edit', @@ -29,7 +27,7 @@ const actionItems = [ const usePoolsColumns = ( handleSelect: (val: string, record: ListItem) => void, sortOrder?: string[] -): SealColumnProps[] => { +): ColumnProps[] => { const intl = useIntl(); return useMemo(() => { diff --git a/src/pages/cluster-management/step-forms/advance-config.tsx b/src/pages/cluster-management/step-forms/advance-config.tsx index 7392cdb9..7806dd3b 100644 --- a/src/pages/cluster-management/step-forms/advance-config.tsx +++ b/src/pages/cluster-management/step-forms/advance-config.tsx @@ -1,8 +1,6 @@ -import IconFont from '@/components/icon-font'; -import SealInput from '@/components/seal-form/seal-input'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import YamlEditor from '@/pages/_components/yaml-editor'; +import { Input as CInput, IconFont, YamlEditor } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Form } from 'antd'; import React, { forwardRef, useEffect, useImperativeHandle } from 'react'; @@ -71,7 +69,7 @@ const ClusterAdvanceConfig: React.FC<{ } ]} > - + {provider === ProviderValueMap.Kubernetes && ( diff --git a/src/pages/cluster-management/step-forms/worker-pools-form.tsx b/src/pages/cluster-management/step-forms/worker-pools-form.tsx index 69fd6d14..3ea71d30 100644 --- a/src/pages/cluster-management/step-forms/worker-pools-form.tsx +++ b/src/pages/cluster-management/step-forms/worker-pools-form.tsx @@ -1,6 +1,6 @@ -import PageTools from '@/components/page-tools'; import { PageActionType } from '@/config/types'; import { PlusOutlined } from '@ant-design/icons'; +import { PageTools } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, FormInstance } from 'antd'; import { diff --git a/src/pages/dashboard/components/active-table.tsx b/src/pages/dashboard/components/active-table.tsx index 82151e22..b6882cf5 100644 --- a/src/pages/dashboard/components/active-table.tsx +++ b/src/pages/dashboard/components/active-table.tsx @@ -1,12 +1,10 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import PageTools from '@/components/page-tools'; import { modelCategoriesMap } from '@/pages/llmodels/config'; import { convertFileSize } from '@/utils'; +import { AutoTooltip, PageTools } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Col, Row, Table } from 'antd'; import { useContext } from 'react'; import { DashboardContext } from '../config/dashboard-context'; - const NACategories = [ modelCategoriesMap.llm, modelCategoriesMap.embedding, diff --git a/src/pages/dashboard/components/resource-utilization.tsx b/src/pages/dashboard/components/resource-utilization.tsx index a801e6c4..4347d6a3 100644 --- a/src/pages/dashboard/components/resource-utilization.tsx +++ b/src/pages/dashboard/components/resource-utilization.tsx @@ -1,4 +1,4 @@ -import LineChart from '@/components/echarts/line-chart'; +import { LineChart } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import dayjs from 'dayjs'; import _ from 'lodash'; diff --git a/src/pages/dashboard/components/system-load.tsx b/src/pages/dashboard/components/system-load.tsx index d2e90e52..c26a70dc 100644 --- a/src/pages/dashboard/components/system-load.tsx +++ b/src/pages/dashboard/components/system-load.tsx @@ -1,15 +1,16 @@ -import CardWrapper from '@/components/card-wrapper'; -import GaugeChart from '@/components/echarts/gauge'; -import PageTools from '@/components/page-tools'; -import BaseSelect from '@/components/seal-form/base/select'; import { queryClusterList } from '@/pages/cluster-management/apis'; +import { + BaseSelect, + CardWrapper, + GaugeChart, + PageTools +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Col, Row } from 'antd'; import _ from 'lodash'; import { useContext, useEffect, useMemo, useState } from 'react'; import { DashboardContext } from '../config/dashboard-context'; import ResourceUtilization from './resource-utilization'; - const smallChartHeight = 190; const largeChartHeight = 400; const resourceChartHeight = 400; diff --git a/src/pages/dashboard/components/usage-inner/export-data.tsx b/src/pages/dashboard/components/usage-inner/export-data.tsx index cb424bb1..68be9295 100644 --- a/src/pages/dashboard/components/usage-inner/export-data.tsx +++ b/src/pages/dashboard/components/usage-inner/export-data.tsx @@ -1,7 +1,5 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import ModalFooter from '@/components/modal-footer'; -import ScrollerModal from '@/components/scroller-modal'; import { exportJsonToExcel } from '@/utils/excel-reader'; +import { AutoTooltip, ModalFooter, ScrollerModal } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Table, TableColumnType } from 'antd'; import dayjs from 'dayjs'; @@ -10,7 +8,6 @@ import { DASHBOARD_USAGE_API } from '../../apis'; import { TableRow } from '../../config/types'; import FilterBar from './filter-bar'; import useUsageData from './use-usage-data'; - const ExportData: React.FC<{ open: boolean; onCancel: () => void; diff --git a/src/pages/dashboard/components/usage-inner/filter-bar.tsx b/src/pages/dashboard/components/usage-inner/filter-bar.tsx index c7f7fe09..416ea4ae 100644 --- a/src/pages/dashboard/components/usage-inner/filter-bar.tsx +++ b/src/pages/dashboard/components/usage-inner/filter-bar.tsx @@ -1,8 +1,10 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import SealCascader from '@/components/seal-form/seal-cascader'; -import SimpleSelect from '@/components/seal-form/simple-select'; import ProviderLogo from '@/pages/maas-provider/components/provider-logo'; import { DownloadOutlined } from '@ant-design/icons'; +import { + AutoTooltip, + Cascader as SealCascader, + SimpleSelect +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, DatePicker, Tooltip } from 'antd'; import dayjs from 'dayjs'; @@ -10,7 +12,6 @@ import React from 'react'; import { DASHBOARD_STATS_API } from '../../apis'; import useRangePickerPreset from '../../hooks/use-rangepicker-preset'; import FilterBarCss from '../../styles/filter-bar.less'; - const DefaultDateConfig = { maxRange: 60, defaultRange: 29 diff --git a/src/pages/dashboard/components/usage-inner/request-token-inner.tsx b/src/pages/dashboard/components/usage-inner/request-token-inner.tsx index 3b01e140..216b7022 100644 --- a/src/pages/dashboard/components/usage-inner/request-token-inner.tsx +++ b/src/pages/dashboard/components/usage-inner/request-token-inner.tsx @@ -1,7 +1,5 @@ -import CardWrapper from '@/components/card-wrapper'; -import { SimpleCard } from '@/components/card-wrapper/simple-card'; -import MixLineBar from '@/components/echarts/mix-line-bar'; import { formatLargeNumber } from '@/utils'; +import { CardWrapper, MixLineBarChart, SimpleCard } from '@gpustack/core-ui'; import { Button } from 'antd'; import dayjs from 'dayjs'; import React, { useMemo } from 'react'; @@ -103,7 +101,7 @@ const RequestTokenInner: React.FC = (props) => { - = (props) => { smooth={false} legendData={legendData} labelFormatter={labelFormatter} - > + > ); diff --git a/src/pages/dashboard/components/usage-inner/top-user.tsx b/src/pages/dashboard/components/usage-inner/top-user.tsx index 3dfbb21d..c7b3c209 100644 --- a/src/pages/dashboard/components/usage-inner/top-user.tsx +++ b/src/pages/dashboard/components/usage-inner/top-user.tsx @@ -1,5 +1,4 @@ -import CardWrapper from '@/components/card-wrapper'; -import HBar from '@/components/echarts/h-bar'; +import { CardWrapper, HBarChart } from '@gpustack/core-ui'; import React from 'react'; interface TopUserProps { @@ -13,12 +12,12 @@ const TopUser: React.FC = (props) => { return ( - + > ); }; diff --git a/src/pages/dashboard/hooks/use-add-resource.tsx b/src/pages/dashboard/hooks/use-add-resource.tsx index 409a9600..3fe0936a 100644 --- a/src/pages/dashboard/hooks/use-add-resource.tsx +++ b/src/pages/dashboard/hooks/use-add-resource.tsx @@ -1,9 +1,8 @@ import { clusterSessionAtom } from '@/atoms/clusters'; import { hideModalTemporarilyAtom } from '@/atoms/settings'; -import IconFont from '@/components/icon-font'; -import ScrollerModal from '@/components/scroller-modal/index'; import useUserSettings from '@/hooks/use-user-settings'; import useClusterList from '@/pages/cluster-management/hooks/use-cluster-list'; +import { IconFont, ScrollerModal } from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { Button } from 'antd'; import { useAtom } from 'jotai'; diff --git a/src/pages/llmodels/catalog.tsx b/src/pages/llmodels/catalog.tsx index fc3e4507..f6df02ae 100644 --- a/src/pages/llmodels/catalog.tsx +++ b/src/pages/llmodels/catalog.tsx @@ -1,12 +1,14 @@ import { modelsExpandKeysAtom, modelsSessionAtom } from '@/atoms/models'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import useBodyScroll from '@/hooks/use-body-scroll'; import useTableFetch from '@/hooks/use-table-fetch'; -import { ScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context'; import { IS_FIRST_LOGIN, writeState } from '@/utils/localstore/index'; import { SearchOutlined } from '@ant-design/icons'; +import { + FilterBar, + IconFont, + InfiniteScrollerProvider +} from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { message } from 'antd'; import { useAtom } from 'jotai'; @@ -143,7 +145,7 @@ const Catalog: React.FC = () => { buttonIcon={} widths={{ input: 230, select: 200 }} > - { title={intl.formatMessage({ id: 'noresult.catalog.title' })} subTitle={intl.formatMessage({ id: 'noresult.catalog.subTitle' })} > - + = { [modelCategoriesMap.embedding]: { api: EMBEDDING_API diff --git a/src/pages/llmodels/components/catalog/catalog-item.tsx b/src/pages/llmodels/components/catalog/catalog-item.tsx index 47f3b8f1..6b93eff5 100644 --- a/src/pages/llmodels/components/catalog/catalog-item.tsx +++ b/src/pages/llmodels/components/catalog/catalog-item.tsx @@ -1,8 +1,6 @@ import fallbackImg from '@/assets/images/img.png'; -import AutoTooltip from '@/components/auto-tooltip'; -import IconFont from '@/components/icon-font'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; import { categoryConfig } from '@/pages/_components/model-tag'; +import { AutoTooltip, IconFont, ThemeTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Typography } from 'antd'; import classNames from 'classnames'; @@ -11,7 +9,6 @@ import React, { useCallback, useMemo } from 'react'; import { modelCategories } from '../../config'; import { CatalogItem as CatalogItemType } from '../../config/types'; import '../../style/catalog-item.less'; - interface CatalogItemProps { activeId: number; data: CatalogItemType; diff --git a/src/pages/llmodels/components/catalog/catalog-list.tsx b/src/pages/llmodels/components/catalog/catalog-list.tsx index 2ba2a2a3..8f0d1fd7 100644 --- a/src/pages/llmodels/components/catalog/catalog-list.tsx +++ b/src/pages/llmodels/components/catalog/catalog-list.tsx @@ -1,7 +1,9 @@ -import ResizeContainer from '@/components/resize-container'; -import CatalogSkelton from '@/components/templates/card-skelton'; -import InfiniteScroller from '@/pages/_components/infinite-scroller'; -import { useScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context'; +import { + InfiniteScroller, + ResizeContainer, + TemplateCardSkeleton +} from '@gpustack/core-ui'; +import { useScrollerContext } from '@gpustack/core-ui/lib/components/infinite-scroller/use-scroller-context'; import { Spin } from 'antd'; import React from 'react'; import styled from 'styled-components'; @@ -45,7 +47,7 @@ const ListSkeleton: React.FC<{ root: 'skelton-wrapper' }} > - {isFirst && } + {isFirst && } )} diff --git a/src/pages/llmodels/components/compatible-alert.tsx b/src/pages/llmodels/components/compatible-alert.tsx index 379fa0d4..d2e906d5 100644 --- a/src/pages/llmodels/components/compatible-alert.tsx +++ b/src/pages/llmodels/components/compatible-alert.tsx @@ -1,5 +1,5 @@ -import AlertBlockInfo from '@/components/alert-info/block'; import { CloseOutlined } from '@ant-design/icons'; +import { AlertBlockInfo } from '@gpustack/core-ui'; import { Button } from 'antd'; import { isArray } from 'lodash'; import React, { useCallback, useMemo } from 'react'; diff --git a/src/pages/llmodels/components/deployment/deploy-builtin-modal.tsx b/src/pages/llmodels/components/deployment/deploy-builtin-modal.tsx index f5c34e97..3a17dd81 100644 --- a/src/pages/llmodels/components/deployment/deploy-builtin-modal.tsx +++ b/src/pages/llmodels/components/deployment/deploy-builtin-modal.tsx @@ -1,9 +1,7 @@ -import ModalFooter from '@/components/modal-footer'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; import { PageActionType } from '@/config/types'; import { createAxiosToken } from '@/hooks/use-chunk-request'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; import { ClusterStatusValueMap } from '@/pages/cluster-management/config'; +import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, message } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/llmodels/components/deployment/deploy-modal.tsx b/src/pages/llmodels/components/deployment/deploy-modal.tsx index 61e99663..ba8d5033 100644 --- a/src/pages/llmodels/components/deployment/deploy-modal.tsx +++ b/src/pages/llmodels/components/deployment/deploy-modal.tsx @@ -1,9 +1,8 @@ import { getRequestId } from '@/atoms/models'; -import ModalFooter from '@/components/modal-footer'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; import { PageActionType } from '@/config/types'; import useDeferredRequest from '@/hooks/use-deferred-request'; import { ClusterStatusValueMap } from '@/pages/cluster-management/config'; +import { GSDrawer, ModalFooter } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { Button } from 'antd'; @@ -349,7 +348,7 @@ const AddModal: FC = (props) => { updateSelectedModel(item); - let warningStatus: MessageStatus = { + const warningStatus: MessageStatus = { show: true, title: '', type: 'transition', @@ -496,7 +495,7 @@ const AddModal: FC = (props) => { source: source }); } else { - let backend = checkOnlyAscendNPU(gpuOptions) + const backend = checkOnlyAscendNPU(gpuOptions) ? backendOptionsMap.ascendMindie : backendOptionsMap.vllm; diff --git a/src/pages/llmodels/components/deployment/update-modal.tsx b/src/pages/llmodels/components/deployment/update-modal.tsx index 6d5fa713..40d9c542 100644 --- a/src/pages/llmodels/components/deployment/update-modal.tsx +++ b/src/pages/llmodels/components/deployment/update-modal.tsx @@ -1,8 +1,6 @@ -import ModalFooter from '@/components/modal-footer'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; +import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import _ from 'lodash'; import React, { useEffect, useRef } from 'react'; diff --git a/src/pages/llmodels/components/download/index.tsx b/src/pages/llmodels/components/download/index.tsx index 308a5499..5ec29f6d 100644 --- a/src/pages/llmodels/components/download/index.tsx +++ b/src/pages/llmodels/components/download/index.tsx @@ -1,6 +1,5 @@ -import ModalFooter from '@/components/modal-footer'; -import GSDrawer from '@/components/scroller-modal/gs-drawer'; import { ProviderValueMap } from '@/pages/cluster-management/config'; +import { GSDrawer, ModalFooter } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { debounce } from 'lodash'; import React, { useCallback, useEffect, useRef, useState } from 'react'; diff --git a/src/pages/llmodels/components/download/target-form.tsx b/src/pages/llmodels/components/download/target-form.tsx index 3c7cd3f8..7c2a9707 100644 --- a/src/pages/llmodels/components/download/target-form.tsx +++ b/src/pages/llmodels/components/download/target-form.tsx @@ -1,9 +1,11 @@ -import SealCascader from '@/components/seal-form/seal-cascader'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; -import TooltipList from '@/components/tooltip-list'; import useAppUtils from '@/hooks/use-app-utils'; import { ModelFileFormData as FormData } from '@/pages/resources/config/types'; +import { + Input as CInput, + Cascader as SealCascader, + Select as SealSelect, + TooltipList +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -131,12 +133,12 @@ const TargetForm: React.FC = forwardRef((props, ref) => { } ]} > - } - > + > ); @@ -222,7 +224,7 @@ const TargetForm: React.FC = forwardRef((props, ref) => { } ]} > - = forwardRef((props, ref) => { label={intl.formatMessage({ id: 'resources.modelfiles.form.localdir' })} - > + > )} diff --git a/src/pages/llmodels/components/gpu-card.tsx b/src/pages/llmodels/components/gpu-card.tsx index 7e7f1d5b..2454f780 100644 --- a/src/pages/llmodels/components/gpu-card.tsx +++ b/src/pages/llmodels/components/gpu-card.tsx @@ -1,11 +1,10 @@ -import AutoTooltip from '@/components/auto-tooltip'; import { convertFileSize } from '@/utils'; +import { AutoTooltip } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import _ from 'lodash'; import React from 'react'; import styled from 'styled-components'; import '../style/gpu-card.less'; - const CardWrapper = styled.div` display: flex; gap: 8px; diff --git a/src/pages/llmodels/components/incompatiable-info.tsx b/src/pages/llmodels/components/incompatiable-info.tsx index d7d666b0..b9d13348 100644 --- a/src/pages/llmodels/components/incompatiable-info.tsx +++ b/src/pages/llmodels/components/incompatiable-info.tsx @@ -1,5 +1,5 @@ -import { TooltipOverlayScroller } from '@/components/overlay-scroller'; import { LoadingOutlined, WarningOutlined } from '@ant-design/icons'; +import { TooltipOverlayScroller } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tag, Tooltip } from 'antd'; import React from 'react'; diff --git a/src/pages/llmodels/components/instance-cells/actions-cell.tsx b/src/pages/llmodels/components/instance-cells/actions-cell.tsx index db644f93..cf610c61 100644 --- a/src/pages/llmodels/components/instance-cells/actions-cell.tsx +++ b/src/pages/llmodels/components/instance-cells/actions-cell.tsx @@ -1,9 +1,11 @@ -import DropdownButtons from '@/components/drop-down-buttons'; -import IconFont from '@/components/icon-font'; -import { HandlerOptions } from '@/hooks/use-chunk-fetch'; -import useDownloadStream from '@/hooks/use-download-stream'; import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-benchmark'; import { DeleteOutlined, DownloadOutlined } from '@ant-design/icons'; +import { + DropdownButtons, + IconFont, + useDownloadStream +} from '@gpustack/core-ui'; +import { HandlerOptions } from '@gpustack/core-ui/lib/hooks/use-chunk-fetch'; import { useIntl } from '@umijs/max'; import { Progress, notification } from 'antd'; import dayjs from 'dayjs'; diff --git a/src/pages/llmodels/components/instance-cells/cpu-offloading-cell.tsx b/src/pages/llmodels/components/instance-cells/cpu-offloading-cell.tsx index e81514c0..0ff45337 100644 --- a/src/pages/llmodels/components/instance-cells/cpu-offloading-cell.tsx +++ b/src/pages/llmodels/components/instance-cells/cpu-offloading-cell.tsx @@ -1,6 +1,5 @@ -import InfoColumn from '@/components/simple-table/info-column'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; import { InfoCircleOutlined } from '@ant-design/icons'; +import { InfoColumn, ThemeTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tooltip } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/llmodels/components/instance-cells/distribute-info-cell.tsx b/src/pages/llmodels/components/instance-cells/distribute-info-cell.tsx index 5cead539..9966c4ce 100644 --- a/src/pages/llmodels/components/instance-cells/distribute-info-cell.tsx +++ b/src/pages/llmodels/components/instance-cells/distribute-info-cell.tsx @@ -1,9 +1,12 @@ -import { TooltipOverlayScroller } from '@/components/overlay-scroller'; -import SimpleTabel, { ColumnProps } from '@/components/simple-table'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; import { ListItem as WorkerListItem } from '@/pages/resources/config/types'; import { convertFileSize } from '@/utils'; import { InfoCircleOutlined } from '@ant-design/icons'; +import { + SimpleTable, + ThemeTag, + TooltipOverlayScroller, + type ColumnProps +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import _ from 'lodash'; import React from 'react'; @@ -114,11 +117,11 @@ const DistributedServerList: React.FC = ({ return (
    - + >
    ); }; diff --git a/src/pages/llmodels/components/instance-cells/downloading-status-cell.tsx b/src/pages/llmodels/components/instance-cells/downloading-status-cell.tsx index 92223f71..348726e7 100644 --- a/src/pages/llmodels/components/instance-cells/downloading-status-cell.tsx +++ b/src/pages/llmodels/components/instance-cells/downloading-status-cell.tsx @@ -1,6 +1,6 @@ -import SimpleTabel, { ColumnProps } from '@/components/simple-table'; -import StatusTag from '@/components/status-tag'; import { ListItem as WorkerListItem } from '@/pages/resources/config/types'; +import { SimpleTable, StatusTag } from '@gpustack/core-ui'; +import { type ColumnProps } from '@gpustack/core-ui/lib/components/simple-table'; import { Progress, Tooltip } from 'antd'; import _ from 'lodash'; import { InstanceStatusMap, status } from '../../config'; @@ -102,21 +102,21 @@ const DownloadingTips = (props: { return (
    {severList.length > 0 && ( - + > )} {draftModelList.length > 0 && ( - + > )}
    ); diff --git a/src/pages/llmodels/components/instance-cells/instance-status-cell.tsx b/src/pages/llmodels/components/instance-cells/instance-status-cell.tsx index e7cd653c..31121ea2 100644 --- a/src/pages/llmodels/components/instance-cells/instance-status-cell.tsx +++ b/src/pages/llmodels/components/instance-cells/instance-status-cell.tsx @@ -1,4 +1,4 @@ -import StatusTag from '@/components/status-tag'; +import { StatusTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button } from 'antd'; import React from 'react'; diff --git a/src/pages/llmodels/components/instance-cells/name-cell.tsx b/src/pages/llmodels/components/instance-cells/name-cell.tsx index 47f3120c..1bf98ca8 100644 --- a/src/pages/llmodels/components/instance-cells/name-cell.tsx +++ b/src/pages/llmodels/components/instance-cells/name-cell.tsx @@ -1,5 +1,3 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import IconFont from '@/components/icon-font'; import { convertFileSize } from '@/utils'; import { HddFilled, @@ -7,13 +5,13 @@ import { PieChartFilled, ThunderboltFilled } from '@ant-design/icons'; +import { AutoTooltip, IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tooltip } from 'antd'; import _ from 'lodash'; import React, { useEffect } from 'react'; import { ModelInstanceListItem } from '../../config/types'; import '../../style/instance-item.less'; - export interface NameCellProps { record: ModelInstanceListItem; modelData: any; diff --git a/src/pages/llmodels/components/instance/instance-item.tsx b/src/pages/llmodels/components/instance/instance-item.tsx index fd199657..7ebad176 100644 --- a/src/pages/llmodels/components/instance/instance-item.tsx +++ b/src/pages/llmodels/components/instance/instance-item.tsx @@ -1,6 +1,5 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import RowChildren from '@/components/seal-table/components/row-children'; import { ListItem as WorkerListItem } from '@/pages/resources/config/types'; +import { AutoTooltip, RowChildren } from '@gpustack/core-ui'; import { Col, Row } from 'antd'; import dayjs from 'dayjs'; import React from 'react'; @@ -12,7 +11,6 @@ import DistributeInfoCell from '../instance-cells/distribute-info-cell'; import DownloadingStatusCell from '../instance-cells/downloading-status-cell'; import InstanceStatusCell from '../instance-cells/instance-status-cell'; import NameCell from '../instance-cells/name-cell'; - interface InstanceItemProps { instanceData: ModelInstanceListItem; workerList: WorkerListItem[]; diff --git a/src/pages/llmodels/components/left-filters.tsx b/src/pages/llmodels/components/left-filters.tsx index dcdc8ec6..f720b666 100644 --- a/src/pages/llmodels/components/left-filters.tsx +++ b/src/pages/llmodels/components/left-filters.tsx @@ -1,5 +1,5 @@ -import { FiltersButton } from '@/components/page-tools/index'; import { SearchOutlined, SyncOutlined } from '@ant-design/icons'; +import { FiltersButton } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Input, Space } from 'antd'; import React from 'react'; diff --git a/src/pages/llmodels/components/model-item.tsx b/src/pages/llmodels/components/model-item.tsx index f1436928..ccdd7750 100644 --- a/src/pages/llmodels/components/model-item.tsx +++ b/src/pages/llmodels/components/model-item.tsx @@ -1,8 +1,10 @@ -import IconFont from '@/components/icon-font'; -import StatusTag from '@/components/status-tag'; -import TagWrapper from '@/components/tags-wrapper'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; -import Card from '@/components/templates/card'; +import { + IconFont, + StatusTag, + TagsWrapper, + TemplateCard, + ThemeTag +} from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { Button } from 'antd'; import _ from 'lodash'; @@ -163,7 +165,7 @@ const ModelItem: React.FC<{ return ( - onClick(model)} clickable={false} @@ -222,11 +224,11 @@ const ModelItem: React.FC<{ {model.meta?.voices?.length > 0 && ( <> - + > )} @@ -243,7 +245,7 @@ const ModelItem: React.FC<{ - + ); }; diff --git a/src/pages/llmodels/components/model-source/hf-model-file.tsx b/src/pages/llmodels/components/model-source/hf-model-file.tsx index a5ab148d..3957904f 100644 --- a/src/pages/llmodels/components/model-source/hf-model-file.tsx +++ b/src/pages/llmodels/components/model-source/hf-model-file.tsx @@ -1,6 +1,5 @@ import { getRequestId } from '@/atoms/models'; -import BaseSelect from '@/components/seal-form/base/select'; -import SimpleOverlay from '@/components/simple-overlay'; +import { BaseSelect, SimpleOverlay } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Empty, Spin } from 'antd'; import _ from 'lodash'; @@ -22,7 +21,6 @@ import '../../style/hf-model-file.less'; import TitleWrapper from '../title-wrapper'; import FileSkeleton from './file-skeleton'; import ModelFileItem from './model-file-item'; - const ItemFileWrapper = styled.div` display: flex; flex-direction: column; diff --git a/src/pages/llmodels/components/model-source/hf-model-item.tsx b/src/pages/llmodels/components/model-source/hf-model-item.tsx index a388553d..a7bf01c2 100644 --- a/src/pages/llmodels/components/model-source/hf-model-item.tsx +++ b/src/pages/llmodels/components/model-source/hf-model-item.tsx @@ -1,6 +1,6 @@ -import IconFont from '@/components/icon-font'; import { formatNumber } from '@/utils'; import { DownloadOutlined, HeartOutlined } from '@ant-design/icons'; +import { IconFont } from '@gpustack/core-ui'; import classNames from 'classnames'; import dayjs from 'dayjs'; import React from 'react'; diff --git a/src/pages/llmodels/components/model-source/model-card.tsx b/src/pages/llmodels/components/model-source/model-card.tsx index 42a618ec..63ae1a27 100644 --- a/src/pages/llmodels/components/model-source/model-card.tsx +++ b/src/pages/llmodels/components/model-source/model-card.tsx @@ -1,7 +1,3 @@ -import IconFont from '@/components/icon-font'; -import MarkdownViewer from '@/components/markdown-viewer'; -import SimpleOverlay from '@/components/simple-overlay'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; import { GPUSTACK_API_BASE_URL } from '@/config/settings'; import useRequestToken from '@/hooks/use-request-token'; import { @@ -9,6 +5,12 @@ import { FileMarkdownOutlined, RightOutlined } from '@ant-design/icons'; +import { + IconFont, + MarkdownViewer, + SimpleOverlay, + ThemeTag +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Empty, Spin, Tooltip } from 'antd'; import { some } from 'lodash'; @@ -131,7 +133,7 @@ const ModelCard: React.FC<{ }; const removeMetadata = useCallback((str: string) => { - let indexes = []; + const indexes = []; let index = str.indexOf('---'); while (index !== -1) { diff --git a/src/pages/llmodels/components/model-source/model-file-item.tsx b/src/pages/llmodels/components/model-source/model-file-item.tsx index c1c6e395..cc9cca46 100644 --- a/src/pages/llmodels/components/model-source/model-file-item.tsx +++ b/src/pages/llmodels/components/model-source/model-file-item.tsx @@ -1,7 +1,6 @@ -import { TooltipOverlayScroller } from '@/components/overlay-scroller'; -import ThemeTag from '@/components/tags-wrapper/theme-tag'; import { convertFileSize } from '@/utils'; import { InfoCircleOutlined } from '@ant-design/icons'; +import { ThemeTag, TooltipOverlayScroller } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import classNames from 'classnames'; import _ from 'lodash'; diff --git a/src/pages/llmodels/components/model-source/search-input.tsx b/src/pages/llmodels/components/model-source/search-input.tsx index 3f488180..15b7d07c 100644 --- a/src/pages/llmodels/components/model-source/search-input.tsx +++ b/src/pages/llmodels/components/model-source/search-input.tsx @@ -1,6 +1,6 @@ -import IconFont from '@/components/icon-font'; import hotkeys from '@/config/hotkeys'; import { SearchOutlined } from '@ant-design/icons'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Input } from 'antd'; import React, { useRef } from 'react'; diff --git a/src/pages/llmodels/components/model-source/search-model.tsx b/src/pages/llmodels/components/model-source/search-model.tsx index 7b271533..33dad8b5 100644 --- a/src/pages/llmodels/components/model-source/search-model.tsx +++ b/src/pages/llmodels/components/model-source/search-model.tsx @@ -1,7 +1,6 @@ import { getRequestId, setRquestId } from '@/atoms/models'; -import BaseSelect from '@/components/seal-form/base/select'; import { createAxiosToken } from '@/hooks/use-chunk-request'; -import ColumnWrapper from '@/pages/_components/column-wrapper'; +import { BaseSelect, ColumnWrapper } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Pagination } from 'antd'; import _ from 'lodash'; @@ -23,7 +22,6 @@ import useRecognizeAudio from '../../hooks/use-recognize-audio'; import SearchStyle from '../../style/search-result.less'; import SearchInput from './search-input'; import SearchResult from './search-result'; - const filterOptions = [ { label: 'FP8', value: 'fp8' }, { label: 'AWQ', value: 'awq' }, @@ -173,7 +171,7 @@ const SearchModel: React.FC = (props) => { if (getRequestId() !== currentSearchId) { throw 'new request has been sent'; } - let list = _.map(data || [], (item: any) => { + const list = _.map(data || [], (item: any) => { return { ...item, value: item.name, @@ -210,28 +208,31 @@ const SearchModel: React.FC = (props) => { throw 'new request has been sent'; } - let list = _.map(_.get(data, 'Data.Model.Models') || [], (item: any) => { - return { - path: item.Path, - name: `${item.Path}/${item.Name}`, - downloads: item.Downloads, - id: `${item.Path}/${item.Name}`, - updatedAt: item.LastUpdatedTime * 1000, - likes: item.Stars, - value: item.Name, - label: item.Name, - revision: item.Revision, - task: item.Tasks?.map((sItem: any) => sItem.Name).join(','), - tags: item.Tags, - libraries: item.Libraries, - avatar: item.Avatar, - isGGUF: checkIsGGUF({ + const list = _.map( + _.get(data, 'Data.Model.Models') || [], + (item: any) => { + return { + path: item.Path, + name: `${item.Path}/${item.Name}`, + downloads: item.Downloads, + id: `${item.Path}/${item.Name}`, + updatedAt: item.LastUpdatedTime * 1000, + likes: item.Stars, + value: item.Name, + label: item.Name, + revision: item.Revision, + task: item.Tasks?.map((sItem: any) => sItem.Name).join(','), tags: item.Tags, - libraries: item.Libraries - }), - source: modelSource - }; - }); + libraries: item.Libraries, + avatar: item.Avatar, + isGGUF: checkIsGGUF({ + tags: item.Tags, + libraries: item.Libraries + }), + source: modelSource + }; + } + ); setPaginationInfo((prev) => { return { diff --git a/src/pages/llmodels/components/model-source/search-result.tsx b/src/pages/llmodels/components/model-source/search-result.tsx index ceaab557..665244fa 100644 --- a/src/pages/llmodels/components/model-source/search-result.tsx +++ b/src/pages/llmodels/components/model-source/search-result.tsx @@ -1,5 +1,5 @@ -import IconFont from '@/components/icon-font'; import { SearchOutlined } from '@ant-design/icons'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Empty, Spin } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/llmodels/components/scaling.tsx b/src/pages/llmodels/components/scaling.tsx deleted file mode 100644 index a0926d37..00000000 --- a/src/pages/llmodels/components/scaling.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import SealInputNumber from '@/components/seal-form/input-number'; -import useAppUtils from '@/hooks/use-app-utils'; -import { QuestionCircleOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; -import { Checkbox, Form, Tooltip } from 'antd'; -import { CheckboxChangeEvent } from 'antd/es/checkbox'; -import React from 'react'; -import { useFormContext } from '../config/form-context'; - -const scheduleTypeTips = [ - { - title: { - text: 'models.form.scheduletype.auto', - locale: true - }, - tips: 'models.form.scheduletype.auto.tips' - }, - { - title: { - text: 'models.form.scheduletype.manual', - locale: true - }, - tips: 'models.form.scheduletype.manual.tips' - } -]; - -const CheckboxField: React.FC<{ - title: string; - label: string; - checked?: boolean; - onChange?: (e: CheckboxChangeEvent) => void; -}> = ({ title, label, checked, onChange }) => { - return ( - - - {label} - - - - ); -}; - -const Scaling: React.FC = () => { - const intl = useIntl(); - const { onValuesChange } = useFormContext(); - const { getRuleMessage } = useAppUtils(); - const form = Form.useFormInstance(); - - return ( - <> -
    - - name="enable_auto_scaling" - valuePropName="checked" - style={{ padding: '0 10px', marginBottom: 0 }} - noStyle - > - - -
    - - name="min_replicas" - rules={[ - { - required: true - } - ]} - > - - - - name="max_replicas" - rules={[ - { - required: true - } - ]} - > - - - - name="scale_to_zero_window" - rules={[ - { - required: true - } - ]} - > - - - - name="scale_down_window" - rules={[ - { - required: true - } - ]} - > - - - - name="scale_up_window" - rules={[ - { - required: true - } - ]} - > - - - - ); -}; - -export default Scaling; diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx index c1d9b8c5..739b78bc 100644 --- a/src/pages/llmodels/components/table-list.tsx +++ b/src/pages/llmodels/components/table-list.tsx @@ -1,10 +1,4 @@ import { modelsExpandKeysAtom, modelsSessionAtom } from '@/atoms/models'; -import DeleteModal from '@/components/delete-modal'; -import DropDownActions from '@/components/drop-down-actions'; -import DropdownButtons from '@/components/drop-down-buttons'; -import PageTools from '@/components/page-tools'; -import SealTable from '@/components/seal-table'; -import { TableOrder } from '@/components/seal-table/types'; import { PageAction } from '@/config'; import { TABLE_SORT_DIRECTIONS } from '@/config/settings'; import { PageActionType } from '@/config/types'; @@ -19,6 +13,14 @@ import useOpenPlayground from '@/pages/model-routes/hooks/use-open-playground'; import useGranfanaLink from '@/pages/resources/hooks/use-grafana-link'; import { handleBatchRequest } from '@/utils'; import { DownOutlined } from '@ant-design/icons'; +import { + DeleteModal, + DropdownActions, + DropdownButtons, + PageTools, + Table as SealTable +} from '@gpustack/core-ui'; +import { TableOrder } from '@gpustack/core-ui/lib/components/table/types'; import { useIntl, useNavigate, useSearchParams } from '@umijs/max'; import { useMemoizedFn, useToggle } from 'ahooks'; import { Button, Space, message } from 'antd'; @@ -164,7 +166,6 @@ const Models: React.FC = ({ type: 'model' }); - const [openLogModal, setOpenLogModal] = useState(false); const [openDeployModal, setOpenDeployModal] = useState<{ show: boolean; width: number | string; @@ -599,23 +600,21 @@ const Models: React.FC = ({ right={ {ActionButton()} - {page !== 'clusters' && ( - + - - )} + {intl?.formatMessage?.({ id: 'models.button.deploy' })} + + { }; const handleOnSortChange = (order: TableOrder | Array) => { - let orderList = Array.isArray(order) ? order : [order]; + const orderList = Array.isArray(order) ? order : [order]; if (orderList[0].columnKey === 'replicas') { orderList.push({ columnKey: 'ready_replicas', @@ -439,7 +439,7 @@ const Models = forwardRef((props, ref) => { })); return ( - { deleteIds={dataSource.deletedIds} filterValues={filterValues} > - + ); }); diff --git a/src/pages/llmodels/filters/index.tsx b/src/pages/llmodels/filters/index.tsx index 844b0ad0..ae32f717 100644 --- a/src/pages/llmodels/filters/index.tsx +++ b/src/pages/llmodels/filters/index.tsx @@ -1,12 +1,10 @@ -import BaseSelect from '@/components/seal-form/base/select'; -import FilterForm from '@/pages/_components/filter-form'; +import { BaseSelect, FilterForm } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import { forwardRef, useImperativeHandle, useRef } from 'react'; import styled from 'styled-components'; import { modelCategories } from '../config'; import useFilterStatus from '../hooks/use-filter-status'; - const Content = styled.div` display: flex; flex-direction: column; diff --git a/src/pages/llmodels/forms/advance-config.tsx b/src/pages/llmodels/forms/advance-config.tsx index f52b8374..200c26ae 100644 --- a/src/pages/llmodels/forms/advance-config.tsx +++ b/src/pages/llmodels/forms/advance-config.tsx @@ -1,9 +1,11 @@ -import LabelSelector from '@/components/label-selector'; -import CheckboxField from '@/components/seal-form/checkbox-field'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import DocLink from '@/pages/_components/doc-link'; import { genericReferLink } from '@/pages/model-routes/config'; +import { + CheckboxField, + LabelSelector, + Select as SealSelect +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/llmodels/forms/backend-parameters-list.tsx b/src/pages/llmodels/forms/backend-parameters-list.tsx index 4d26eb4d..91d57f7f 100644 --- a/src/pages/llmodels/forms/backend-parameters-list.tsx +++ b/src/pages/llmodels/forms/backend-parameters-list.tsx @@ -1,4 +1,4 @@ -import ListInput from '@/components/list-input'; +import { ListInput } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/llmodels/forms/backend.tsx b/src/pages/llmodels/forms/backend.tsx index c3656401..69fbe069 100644 --- a/src/pages/llmodels/forms/backend.tsx +++ b/src/pages/llmodels/forms/backend.tsx @@ -1,7 +1,6 @@ -import SealSelect from '@/components/seal-form/seal-select'; -import TooltipList from '@/components/tooltip-list'; import useAppUtils from '@/hooks/use-app-utils'; import { CaretDownOutlined, InfoCircleOutlined } from '@ant-design/icons'; +import { Select as SealSelect, TooltipList } from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { Form, Select } from 'antd'; import React, { useMemo } from 'react'; diff --git a/src/pages/llmodels/forms/basic.tsx b/src/pages/llmodels/forms/basic.tsx index f58acc2d..71894c7d 100644 --- a/src/pages/llmodels/forms/basic.tsx +++ b/src/pages/llmodels/forms/basic.tsx @@ -1,6 +1,3 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; import { modelNameReg, PageAction } from '@/config'; import { OPENAI_COMPATIBLE } from '@/config/settings'; import useAppUtils from '@/hooks/use-app-utils'; @@ -8,6 +5,11 @@ import { ClusterStatusLabelMap, ClusterStatusValueMap } from '@/pages/cluster-management/config'; +import { + AutoTooltip, + Input as CInput, + Select as SealSelect +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import { useMemo } from 'react'; @@ -21,7 +23,6 @@ import CustomBackend from './custom-backend'; import LocalPathSource from './local-path-source'; import ModeField from './mode-field'; import OnlineSource from './online-source'; - const ClusterOption = styled.span` display: flex; padding: 8px 0; @@ -173,14 +174,14 @@ const BasicForm: React.FC = (props) => { } ]} > - + > {fields.includes('source') && ( @@ -240,7 +241,7 @@ const BasicForm: React.FC = (props) => { } ]} > - = (props) => { { api: `${window.location.origin}/${OPENAI_COMPATIBLE}` } )} min={0} - > + > name="description"> - + > ); diff --git a/src/pages/llmodels/forms/catalog.tsx b/src/pages/llmodels/forms/catalog.tsx index 29043503..bb921aa7 100644 --- a/src/pages/llmodels/forms/catalog.tsx +++ b/src/pages/llmodels/forms/catalog.tsx @@ -1,5 +1,5 @@ -import SealInput from '@/components/seal-form/seal-input'; import useAppUtils from '@/hooks/use-app-utils'; +import { Input as CInput } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React from 'react'; @@ -32,10 +32,10 @@ const CatalogForm: React.FC = () => { } ]} > - + > ); diff --git a/src/pages/llmodels/forms/custom-backend.tsx b/src/pages/llmodels/forms/custom-backend.tsx index 1222afc2..6d57b493 100644 --- a/src/pages/llmodels/forms/custom-backend.tsx +++ b/src/pages/llmodels/forms/custom-backend.tsx @@ -1,6 +1,5 @@ -import SealInput from '@/components/seal-form/seal-input'; -import SealTextArea from '@/components/seal-form/seal-textarea'; import useAppUtils from '@/hooks/use-app-utils'; +import { Input as CInput, Textarea as SealTextArea } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React from 'react'; @@ -44,12 +43,12 @@ const CustomBackend: React.FC = () => { } ]} > - + > name="run_command" diff --git a/src/pages/llmodels/forms/envs-override-popover.tsx b/src/pages/llmodels/forms/envs-override-popover.tsx index 1a02cc43..f0f48f5c 100644 --- a/src/pages/llmodels/forms/envs-override-popover.tsx +++ b/src/pages/llmodels/forms/envs-override-popover.tsx @@ -1,6 +1,9 @@ -import OverlayScroller from '@/components/overlay-scroller'; -import SimpleTabel, { ColumnProps } from '@/components/simple-table'; import { WarningOutlined } from '@ant-design/icons'; +import { + OverlayScroller, + SimpleTable, + type ColumnProps +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Alert, Button, Popover, Radio } from 'antd'; import React, { useMemo } from 'react'; @@ -128,7 +131,7 @@ const EnvsOverridePopover: React.FC = (props) => { } }} > - = forwardRef((props, ref) => { // generate the data is available for the backend including the gpu_ids const handleOk = async (formdata: FormData) => { - let data = _.cloneDeep(formdata); + const data = _.cloneDeep(formdata); data.categories = data.categories ? [data.categories] : []; const gpuSelector = generateGPUIds(data); const allValues = { diff --git a/src/pages/llmodels/forms/kv-cache.tsx b/src/pages/llmodels/forms/kv-cache.tsx index 99af680b..3c16c0b0 100644 --- a/src/pages/llmodels/forms/kv-cache.tsx +++ b/src/pages/llmodels/forms/kv-cache.tsx @@ -1,5 +1,4 @@ -import CheckboxField from '@/components/seal-form/checkbox-field'; -import SealInputNumber from '@/components/seal-form/input-number'; +import { CheckboxField, InputNumber as CInputNumber } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -100,7 +99,7 @@ const KVCacheForm = () => { {kvCacheEnabled && ( <> name={['extended_kv_cache', 'ram_ratio']}> - handleRamRatioChange(value, 'ram_ratio')} label={intl.formatMessage({ id: 'models.form.ramRatio' })} description={intl.formatMessage({ @@ -112,7 +111,7 @@ const KVCacheForm = () => { /> name={['extended_kv_cache', 'ram_size']}> - handleRamSizeInput(value)} label={intl.formatMessage({ id: 'models.form.ramSize' })} description={intl.formatMessage( @@ -127,7 +126,7 @@ const KVCacheForm = () => { /> name={['extended_kv_cache', 'chunk_size']}> - handleRamRatioChange(value, 'chunk_size')} label={intl.formatMessage({ id: 'models.form.chunkSize' })} description={intl.formatMessage({ diff --git a/src/pages/llmodels/forms/local-path-source.tsx b/src/pages/llmodels/forms/local-path-source.tsx index afcf087e..66a0b53d 100644 --- a/src/pages/llmodels/forms/local-path-source.tsx +++ b/src/pages/llmodels/forms/local-path-source.tsx @@ -1,6 +1,5 @@ -import SealInput from '@/components/seal-form/seal-input'; -import TooltipList from '@/components/tooltip-list'; import useAppUtils from '@/hooks/use-app-utils'; +import { Input as CInput, TooltipList } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -91,14 +90,14 @@ const LocalPathForm: React.FC = () => { } ]} > - } - > + > ); diff --git a/src/pages/llmodels/forms/mode-field.tsx b/src/pages/llmodels/forms/mode-field.tsx index 5680e461..b5f10945 100644 --- a/src/pages/llmodels/forms/mode-field.tsx +++ b/src/pages/llmodels/forms/mode-field.tsx @@ -1,11 +1,9 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import SealSelect from '@/components/seal-form/seal-select'; +import { AutoTooltip, Select as SealSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form, Select } from 'antd'; import React from 'react'; import { DeployFormKeyMap } from '../config'; import { useCatalogFormContext, useFormContext } from '../config/form-context'; - const Performance: React.FC = () => { const intl = useIntl(); const { formKey } = useFormContext(); diff --git a/src/pages/llmodels/forms/online-source.tsx b/src/pages/llmodels/forms/online-source.tsx index d8741566..753ec08d 100644 --- a/src/pages/llmodels/forms/online-source.tsx +++ b/src/pages/llmodels/forms/online-source.tsx @@ -1,6 +1,6 @@ -import SealInput from '@/components/seal-form/seal-input'; import { PageAction } from '@/config'; import useAppUtils from '@/hooks/use-app-utils'; +import { Input as CInput } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React from 'react'; @@ -44,22 +44,22 @@ const HuggingFaceForm: React.FC = () => { } ]} > - + > {isGGUF && ( name="huggingface_filename" key="huggingface_filename" > - + > )} @@ -75,22 +75,22 @@ const HuggingFaceForm: React.FC = () => { } ]} > - + > {isGGUF && ( name="model_scope_file_path" key="model_scope_file_path" > - + > )} diff --git a/src/pages/llmodels/forms/schedule-type.tsx b/src/pages/llmodels/forms/schedule-type.tsx index ca97c246..2c225005 100644 --- a/src/pages/llmodels/forms/schedule-type.tsx +++ b/src/pages/llmodels/forms/schedule-type.tsx @@ -1,9 +1,11 @@ -import LabelSelector from '@/components/label-selector'; -import { LabelSelectorContext } from '@/components/label-selector/context'; -import SealCascader from '@/components/seal-form/seal-cascader'; -import SealSelect from '@/components/seal-form/seal-select'; -import TooltipList from '@/components/tooltip-list'; import useAppUtils from '@/hooks/use-app-utils'; +import { + LabelSelector, + LabelSelectorProvider, + Cascader as SealCascader, + Select as SealSelect, + TooltipList +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form, InputNumber } from 'antd'; import _ from 'lodash'; @@ -258,9 +260,7 @@ const ScheduleTypeForm: React.FC = () => { } > - + name="worker_selector" rules={[ @@ -308,7 +308,7 @@ const ScheduleTypeForm: React.FC = () => { } > - + )} diff --git a/src/pages/llmodels/forms/speculative-decode.tsx b/src/pages/llmodels/forms/speculative-decode.tsx index fc65d03e..aa298cde 100644 --- a/src/pages/llmodels/forms/speculative-decode.tsx +++ b/src/pages/llmodels/forms/speculative-decode.tsx @@ -1,9 +1,11 @@ -import AutoComlete from '@/components/seal-form/auto-complete'; -import CheckboxField from '@/components/seal-form/checkbox-field'; -import SealInputNumber from '@/components/seal-form/input-number'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; import useAppUtils from '@/hooks/use-app-utils'; +import { + AutoComplete, + CheckboxField, + Input as CInput, + InputNumber as CInputNumber, + Select as SealSelect +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -154,7 +156,7 @@ const SpeculativeDecode = () => { } ]} > - { }} onBlur={handleOnDraftBlur} onSelect={handleDraftSelect} - > + > )} name={['speculative_config', 'num_draft_tokens']} > - { name={['speculative_config', 'ngram_min_match_length']} > - { name={['speculative_config', 'ngram_max_match_length']} > - { +}: ModelsColumnsHookProps & { targetList: any[] }): ColumnProps[] => { const intl = useIntl(); const systemConfig = useAtomValue(systemConfigAtom); diff --git a/src/pages/llmodels/hooks/use-no-resource-result.tsx b/src/pages/llmodels/hooks/use-no-resource-result.tsx index 714ac119..d0158aa5 100644 --- a/src/pages/llmodels/hooks/use-no-resource-result.tsx +++ b/src/pages/llmodels/hooks/use-no-resource-result.tsx @@ -1,6 +1,5 @@ import { clusterSessionAtom } from '@/atoms/clusters'; -import IconFont from '@/components/icon-font'; -import NoResult from '@/pages/_components/no-result'; +import { IconFont, NoResult } from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { useAtom } from 'jotai'; diff --git a/src/pages/llmodels/hooks/use-view-instance-logs.ts b/src/pages/llmodels/hooks/use-view-instance-logs.ts index d7b03d9a..161db099 100644 --- a/src/pages/llmodels/hooks/use-view-instance-logs.ts +++ b/src/pages/llmodels/hooks/use-view-instance-logs.ts @@ -1,5 +1,5 @@ -import { PageSize } from '@/components/logs-viewer/config'; import useBodyScroll from '@/hooks/use-body-scroll'; +import { PageSize } from '@gpustack/core-ui/lib/components/logs-viewer/config'; import { useState } from 'react'; import { MODEL_INSTANCE_API } from '../apis'; import { InstanceRealtimeLogStatus } from '../config'; diff --git a/src/pages/llmodels/index.tsx b/src/pages/llmodels/index.tsx index d6eea53e..92cea477 100644 --- a/src/pages/llmodels/index.tsx +++ b/src/pages/llmodels/index.tsx @@ -1,5 +1,5 @@ -import IconFont from '@/components/icon-font'; import { PageContainerInner } from '@/pages/_components/page-box'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { Segmented, Tabs } from 'antd'; diff --git a/src/pages/llmodels/instance-view/index.tsx b/src/pages/llmodels/instance-view/index.tsx index 0560b728..30a7dcc6 100644 --- a/src/pages/llmodels/instance-view/index.tsx +++ b/src/pages/llmodels/instance-view/index.tsx @@ -1,10 +1,7 @@ -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings'; import useTableFetch from '@/hooks/use-table-fetch'; -import NoResult from '@/pages/_components/no-result'; import PageBox from '@/pages/_components/page-box'; +import { DeleteModal, FilterBar, IconFont, NoResult } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { ConfigProvider, Table } from 'antd'; diff --git a/src/pages/llmodels/instance-view/left-filters.tsx b/src/pages/llmodels/instance-view/left-filters.tsx index 653543d4..dbb0b3af 100644 --- a/src/pages/llmodels/instance-view/left-filters.tsx +++ b/src/pages/llmodels/instance-view/left-filters.tsx @@ -1,11 +1,10 @@ -import BaseSelect from '@/components/seal-form/base/select'; import { ListItem as workerListItem } from '@/pages/resources/config/types'; import { SearchOutlined, SyncOutlined } from '@ant-design/icons'; +import { BaseSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Input, Space } from 'antd'; import React from 'react'; import useFilterStatus from '../hooks/use-filter-status'; - interface LeftFiltersProps { handleNameChange: (e: React.ChangeEvent) => void; handleClusterChange: (value: number) => void; diff --git a/src/pages/llmodels/instance-view/use-instance-columns.tsx b/src/pages/llmodels/instance-view/use-instance-columns.tsx index 8e8a5d8e..e4f951b8 100644 --- a/src/pages/llmodels/instance-view/use-instance-columns.tsx +++ b/src/pages/llmodels/instance-view/use-instance-columns.tsx @@ -1,10 +1,9 @@ // columns.ts -import AutoTooltip from '@/components/auto-tooltip'; -import IconFont from '@/components/icon-font'; import { tableSorter } from '@/config/settings'; import { ListItem as workerListItem } from '@/pages/resources/config/types'; import { convertFileSize } from '@/utils'; import { ThunderboltFilled } from '@ant-design/icons'; +import { AutoTooltip, IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { ColumnsType } from 'antd/lib/table'; import dayjs from 'dayjs'; @@ -19,7 +18,6 @@ import NameCell, { } from '../components/instance-cells/name-cell'; import { ModelInstanceListItem as ListItem } from '../config/types'; import { calcTotalVram } from '../utils'; - const WorkerInfoContent: React.FC = ({ record, modelData }) => { let workerIp = '-'; if (record.worker_ip) { diff --git a/src/pages/llmodels/user-models.tsx b/src/pages/llmodels/user-models.tsx index 489eb5b5..87d00ef4 100644 --- a/src/pages/llmodels/user-models.tsx +++ b/src/pages/llmodels/user-models.tsx @@ -1,15 +1,17 @@ -import IconFont from '@/components/icon-font'; -import PageTools from '@/components/page-tools'; -import BaseSelect from '@/components/seal-form/base/select'; -import CardList from '@/components/templates/card-list'; import useTableFetch from '@/hooks/use-table-fetch'; import { SyncOutlined } from '@ant-design/icons'; +import { + BaseSelect, + IconFont, + InfiniteScrollerProvider, + NoResult, + PageTools, + TemplateCardList +} from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import useMemoizedFn from 'ahooks/lib/useMemoizedFn'; import { Button, Input, Space } from 'antd'; import React, { useCallback, useMemo } from 'react'; -import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context'; -import NoResult from '../_components/no-result'; import PageBox from '../_components/page-box'; import { MY_MODELS_API, queryMyModels } from './apis'; import ModelItem from './components/model-item'; @@ -19,7 +21,6 @@ import { MyModelsStatusValueMap } from './config'; import { categoryToPathMap } from './config/button-actions'; - const Dot = ({ color }: { color: string }) => { return ( { } > - { refresh: loadMore }} > - + > { title={intl.formatMessage({ id: 'noresult.mymodels.title' })} subTitle={intl.formatMessage({ id: 'noresult.mymodels.subTitle' })} > - + ); }; diff --git a/src/pages/login/components/local-user-form.tsx b/src/pages/login/components/local-user-form.tsx index ea97fd68..683ec509 100644 --- a/src/pages/login/components/local-user-form.tsx +++ b/src/pages/login/components/local-user-form.tsx @@ -1,11 +1,10 @@ -import HighlightCode from '@/components/highlight-code'; -import SealInput from '@/components/seal-form/seal-input'; import externalLinks from '@/constants/external-links'; import { InfoCircleOutlined, LockOutlined, UserOutlined } from '@ant-design/icons'; +import { Input as CInput, HighlightCode } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Checkbox, Divider, Form, FormInstance } from 'antd'; import { createStyles } from 'antd-style'; @@ -93,7 +92,7 @@ const LocalUserForm: React.FC = (props) => { } ]} > - } @@ -114,7 +113,7 @@ const LocalUserForm: React.FC = (props) => { } ]} > - } label={intl.formatMessage({ id: 'common.form.password' })} diff --git a/src/pages/login/components/password-form.tsx b/src/pages/login/components/password-form.tsx index c0010c82..34a02089 100644 --- a/src/pages/login/components/password-form.tsx +++ b/src/pages/login/components/password-form.tsx @@ -1,6 +1,5 @@ import { initialPasswordAtom, userAtom } from '@/atoms/user'; import { resetStorageUserSettings } from '@/atoms/utils'; -import SealInput from '@/components/seal-form/seal-input'; import { PasswordReg } from '@/config'; import { CRYPT_TEXT, @@ -8,6 +7,7 @@ import { writeState } from '@/utils/localstore/index'; import { LockOutlined } from '@ant-design/icons'; +import { Input as CInput } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Form, message } from 'antd'; import CryptoJS from 'crypto-js'; @@ -88,7 +88,7 @@ const PasswordForm: React.FC = () => { } ]} > - } label={intl.formatMessage({ id: 'users.form.newpassword' })} @@ -118,7 +118,7 @@ const PasswordForm: React.FC = () => { }) ]} > - } label={intl.formatMessage({ id: 'users.password.confirm' })} diff --git a/src/pages/maas-provider/components/add-provider-modal.tsx b/src/pages/maas-provider/components/add-provider-modal.tsx index ce768da8..6678d177 100644 --- a/src/pages/maas-provider/components/add-provider-modal.tsx +++ b/src/pages/maas-provider/components/add-provider-modal.tsx @@ -1,5 +1,5 @@ import { PageActionType } from '@/config/types'; -import FormDrawer from '@/pages/_components/form-drawer'; +import { FormDrawer } from '@gpustack/core-ui'; import React, { useRef } from 'react'; import { FormData, MaasProviderItem as ListItem } from '../config/types'; diff --git a/src/pages/maas-provider/components/provider-models.tsx b/src/pages/maas-provider/components/provider-models.tsx index 0baf7be8..db8cdb6a 100644 --- a/src/pages/maas-provider/components/provider-models.tsx +++ b/src/pages/maas-provider/components/provider-models.tsx @@ -1,13 +1,11 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import OverlayScroller from '@/components/overlay-scroller'; import { CheckCircleOutlined } from '@ant-design/icons'; +import { AutoTooltip, OverlayScroller } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Flex, Popover, Tag } from 'antd'; import _ from 'lodash'; import React from 'react'; import { categoryConfig } from '../../_components/model-tag'; import { ProviderModel } from '../config/types'; - interface ProviderModelProps { dataList: ProviderModel[]; } diff --git a/src/pages/maas-provider/config/index.ts b/src/pages/maas-provider/config/index.ts index e4232ec3..34627311 100644 --- a/src/pages/maas-provider/config/index.ts +++ b/src/pages/maas-provider/config/index.ts @@ -1,6 +1,6 @@ -import icons from '@/components/icon-font/icons'; import { StatusMaps } from '@/config'; import { StatusType } from '@/config/types'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; import { ProviderEnum } from './providers'; export { maasProviderLabelMap, maasProviderOptions } from './providers'; diff --git a/src/pages/maas-provider/forms/advance-config.tsx b/src/pages/maas-provider/forms/advance-config.tsx index 4cc361fe..6f5f1948 100644 --- a/src/pages/maas-provider/forms/advance-config.tsx +++ b/src/pages/maas-provider/forms/advance-config.tsx @@ -1,7 +1,5 @@ -import IconFont from '@/components/icon-font'; -import SealInput from '@/components/seal-form/seal-input'; import { PageActionType } from '@/config/types'; -import YamlEditor from '@/pages/_components/yaml-editor'; +import { Input as CInput, IconFont, YamlEditor } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Form } from 'antd'; import React, { forwardRef, useImperativeHandle } from 'react'; @@ -46,7 +44,7 @@ const AdvanceConfig: React.FC<{ } ]} > - + { const intl = useIntl(); const { getRuleMessage } = useAppUtils(); diff --git a/src/pages/maas-provider/forms/basic.tsx b/src/pages/maas-provider/forms/basic.tsx index c00ea244..e6ac46fd 100644 --- a/src/pages/maas-provider/forms/basic.tsx +++ b/src/pages/maas-provider/forms/basic.tsx @@ -1,8 +1,10 @@ -import Password from '@/components/seal-form/password'; -import SealInput from '@/components/seal-form/seal-input'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import useAppUtils from '@/hooks/use-app-utils'; +import { + Input as CInput, + Password, + Select as SealSelect +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import ProviderLogo from '../components/provider-logo'; @@ -10,7 +12,6 @@ import { useFormContext } from '../config/form-context'; import { maasProviderOptions } from '../config/providers'; import { FormData } from '../config/types'; import ProviderConfigs from './provider-configs'; - const Basic: React.FC<{ onAPIKeyBlur?: (e: any) => void; }> = ({ onAPIKeyBlur }) => { @@ -49,7 +50,7 @@ const Basic: React.FC<{ } ]} > - name="description"> - + > ); diff --git a/src/pages/maas-provider/forms/index.tsx b/src/pages/maas-provider/forms/index.tsx index e6f0947b..aa940d1b 100644 --- a/src/pages/maas-provider/forms/index.tsx +++ b/src/pages/maas-provider/forms/index.tsx @@ -1,12 +1,10 @@ -import IconFont from '@/components/icon-font'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import CollapsePanel from '@/pages/_components/collapse-panel'; -import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context'; -import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs'; -import useFinishFailed from '@/pages/_components/scroll-spy-tabs/use-finish-failed'; -import useScrollActiveChange from '@/pages/_components/scroll-spy-tabs/use-scroll-active-change'; import { json2Yaml, yaml2Json } from '@/pages/backends/config'; +import { CollapsePanel, IconFont, ScrollSpyTabs } from '@gpustack/core-ui'; +import { useWrapperContext } from '@gpustack/core-ui/lib/components/column-wrapper/use-wrapper-context'; +import useFinishFailed from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-finish-failed'; +import useScrollActiveChange from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-scroll-active-change'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/maas-provider/forms/model-item.tsx b/src/pages/maas-provider/forms/model-item.tsx index e3321e60..def8f480 100644 --- a/src/pages/maas-provider/forms/model-item.tsx +++ b/src/pages/maas-provider/forms/model-item.tsx @@ -1,5 +1,3 @@ -import AutoComplete from '@/components/seal-form/auto-complete'; -import SealSelect from '@/components/seal-form/seal-select'; import { PageAction } from '@/config'; import { categoryOptions, modelCategoriesMap } from '@/pages/llmodels/config'; import { @@ -7,6 +5,7 @@ import { LoadingOutlined, WarningFilled } from '@ant-design/icons'; +import { AutoComplete, Select as SealSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Form, Tooltip } from 'antd'; import React, { useMemo } from 'react'; diff --git a/src/pages/maas-provider/forms/provider-configs.tsx b/src/pages/maas-provider/forms/provider-configs.tsx index 99d0f5ab..40e58221 100644 --- a/src/pages/maas-provider/forms/provider-configs.tsx +++ b/src/pages/maas-provider/forms/provider-configs.tsx @@ -1,10 +1,8 @@ -import Password from '@/components/seal-form/password'; -import SealInput from '@/components/seal-form/seal-input'; +import { Input as CInput, Password } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import { useFormContext } from '../config/form-context'; import { FormData } from '../config/types'; - const ProviderConfigs = () => { const intl = useIntl(); const form = Form.useFormInstance(); @@ -35,12 +33,12 @@ const ProviderConfigs = () => { key={item.name} > {item.type === 'Input' && ( - + > )} {item.type === 'Password' && ( { } ]} > - + > - + > )} diff --git a/src/pages/maas-provider/forms/supported-models.tsx b/src/pages/maas-provider/forms/supported-models.tsx index 0aea1f7a..50ca99ae 100644 --- a/src/pages/maas-provider/forms/supported-models.tsx +++ b/src/pages/maas-provider/forms/supported-models.tsx @@ -1,5 +1,5 @@ -import MetadataList from '@/components/metadata-list'; import { PageAction } from '@/config'; +import { MetadataList } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/maas-provider/hooks/use-provider-columns.tsx b/src/pages/maas-provider/hooks/use-provider-columns.tsx index 6d494e6a..b8ab34b2 100644 --- a/src/pages/maas-provider/hooks/use-provider-columns.tsx +++ b/src/pages/maas-provider/hooks/use-provider-columns.tsx @@ -1,7 +1,6 @@ // columns.ts -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; import { tableSorter } from '@/config/settings'; +import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tag } from 'antd'; import { ColumnsType } from 'antd/lib/table'; @@ -12,7 +11,6 @@ import ProviderModels from '../components/provider-models'; import { rowActionList } from '../config'; import { maasProviderLabelMap } from '../config/providers'; import { MaasProviderItem, ProviderModel } from '../config/types'; - const useProviderColumns = ( handleSelect: (val: string, record: MaasProviderItem) => void, onCellClick?: (record: MaasProviderItem, dataIndex: string) => void diff --git a/src/pages/maas-provider/hooks/use-query-provider-models.tsx b/src/pages/maas-provider/hooks/use-query-provider-models.tsx index 4654a8d8..3cf13182 100644 --- a/src/pages/maas-provider/hooks/use-query-provider-models.tsx +++ b/src/pages/maas-provider/hooks/use-query-provider-models.tsx @@ -1,5 +1,5 @@ import { createAxiosToken } from '@/hooks/use-chunk-request'; -import ErrorMessageContent from '@/pages/_components/error-message-content'; +import { ErrorMessage } from '@gpustack/core-ui'; import { useRequest } from 'ahooks'; import { message } from 'antd'; import { CancelTokenSource } from 'axios'; @@ -112,9 +112,9 @@ export const useTestProviderModel = () => { if (!response?.accessible) { message.error({ content: ( - + > ) }); } @@ -122,9 +122,9 @@ export const useTestProviderModel = () => { onError: (error) => { message.error({ content: ( - + > ) }); } diff --git a/src/pages/maas-provider/index.tsx b/src/pages/maas-provider/index.tsx index 3a713c4b..5a5afe63 100644 --- a/src/pages/maas-provider/index.tsx +++ b/src/pages/maas-provider/index.tsx @@ -1,9 +1,7 @@ -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings'; import useTableFetch from '@/hooks/use-table-fetch'; +import { DeleteModal, FilterBar, IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { ConfigProvider, message, Table } from 'antd'; diff --git a/src/pages/model-routes/components/add-route-modal.tsx b/src/pages/model-routes/components/add-route-modal.tsx index c82b13c9..1bc1d5ee 100644 --- a/src/pages/model-routes/components/add-route-modal.tsx +++ b/src/pages/model-routes/components/add-route-modal.tsx @@ -1,7 +1,5 @@ -import AlertBlockInfo from '@/components/alert-info/block'; -import ModalFooter from '@/components/modal-footer'; import { PageActionType } from '@/config/types'; -import FormDrawer from '@/pages/_components/form-drawer'; +import { AlertBlockInfo, FormDrawer, ModalFooter } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import React, { useRef } from 'react'; import { FormData, RouteItem as ListItem } from '../config/types'; diff --git a/src/pages/model-routes/components/route-targets.tsx b/src/pages/model-routes/components/route-targets.tsx index 36ab49c2..3e2ad207 100644 --- a/src/pages/model-routes/components/route-targets.tsx +++ b/src/pages/model-routes/components/route-targets.tsx @@ -1,9 +1,11 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; -import RowChildren from '@/components/seal-table/components/row-children'; -import StatusTag from '@/components/status-tag'; import ProviderLogo from '@/pages/maas-provider/components/provider-logo'; import { DeleteOutlined } from '@ant-design/icons'; +import { + AutoTooltip, + DropdownButtons, + RowChildren, + StatusTag +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Col, Row } from 'antd'; import dayjs from 'dayjs'; @@ -11,7 +13,6 @@ import React from 'react'; import styled from 'styled-components'; import { TargetStatus, TargetStatusLabelMap } from '../config'; import { RouteTarget } from '../config/types'; - const CellContent = styled.div` display: flex; align-items: center; diff --git a/src/pages/model-routes/config/index.ts b/src/pages/model-routes/config/index.ts index 90e6c3e6..5a4f6945 100644 --- a/src/pages/model-routes/config/index.ts +++ b/src/pages/model-routes/config/index.ts @@ -1,6 +1,6 @@ -import icons from '@/components/icon-font/icons'; import { StatusMaps } from '@/config'; import { StatusType } from '@/config/types'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; export const TargetStatusValueMap: Record = { Active: 'active', diff --git a/src/pages/model-routes/forms/basic.tsx b/src/pages/model-routes/forms/basic.tsx index fd96f944..25cdbab7 100644 --- a/src/pages/model-routes/forms/basic.tsx +++ b/src/pages/model-routes/forms/basic.tsx @@ -1,9 +1,8 @@ -import CheckboxField from '@/components/seal-form/checkbox-field'; -import SealInput from '@/components/seal-form/seal-input'; import useAppUtils from '@/hooks/use-app-utils'; import CategorySelect from '@/pages/_components/category-select'; import DocLink from '@/pages/_components/doc-link'; import { categoryOptions } from '@/pages/llmodels/config'; +import { CheckboxField, Input as CInput } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import { genericReferLink } from '../config'; @@ -25,7 +24,7 @@ const Basic = () => { } ]} > - @@ -56,12 +55,12 @@ const Basic = () => { > - + > name="generic_proxy" diff --git a/src/pages/model-routes/forms/index.tsx b/src/pages/model-routes/forms/index.tsx index 2daf1175..38076a8c 100644 --- a/src/pages/model-routes/forms/index.tsx +++ b/src/pages/model-routes/forms/index.tsx @@ -1,12 +1,10 @@ -import IconFont from '@/components/icon-font'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; -import CollapsePanel from '@/pages/_components/collapse-panel'; -import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context'; -import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs'; -import useFinishFailed from '@/pages/_components/scroll-spy-tabs/use-finish-failed'; -import useScrollActiveChange from '@/pages/_components/scroll-spy-tabs/use-scroll-active-change'; import { modelCategoriesMap } from '@/pages/llmodels/config'; +import { CollapsePanel, IconFont, ScrollSpyTabs } from '@gpustack/core-ui'; +import { useWrapperContext } from '@gpustack/core-ui/lib/components/column-wrapper/use-wrapper-context'; +import useFinishFailed from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-finish-failed'; +import useScrollActiveChange from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-scroll-active-change'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -87,7 +85,7 @@ const AccessForm: React.FC = forwardRef((props, ref) => { const formatTargets = (values: FormData) => { let targetList = [...(values.targets || [])]; - let fallbackTarget = values.fallback_target; + const fallbackTarget = values.fallback_target; if (fallbackTarget) { const exsitinged = targetList.find((ep) => { diff --git a/src/pages/model-routes/forms/meta-data.tsx b/src/pages/model-routes/forms/meta-data.tsx index 073fbfc7..09030f89 100644 --- a/src/pages/model-routes/forms/meta-data.tsx +++ b/src/pages/model-routes/forms/meta-data.tsx @@ -1,8 +1,10 @@ -import SingleImage from '@/components/auto-image/single-image'; -import ListInput from '@/components/list-input'; -import SealInputNumber from '@/components/seal-form/input-number'; -import SealInput from '@/components/seal-form/seal-input'; import UploadImg from '@/pages/playground/components/upload-img'; +import { + Input as CInput, + InputNumber as CInputNumber, + ListInput, + SingleImage +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Form } from 'antd'; import styled from 'styled-components'; @@ -62,26 +64,26 @@ const MetaData = () => { name={['meta', 'size']} normalize={(v) => (v === 0 ? null : v)} > - + > name={['meta', 'activated_size']} normalize={(v) => (v === 0 ? null : v)} > - + > name={['meta', 'max_tokens']}> - { { id: 'common.help.eg' }, { content: 'context/128k' } )} - > + > name={['meta', 'dimensions']} normalize={(v) => (v === 0 ? null : v)} > - + > name={['meta', 'release_date']}> - { { id: 'common.help.eg' }, { content: '2025-05-19' } )} - > + > name={['meta', 'tags']} data-field="metadata"> void, onCellClick?: (record: RouteItem, dataIndex: string) => void -): SealColumnProps[] => { +): ColumnProps[] => { const intl = useIntl(); const filterActions = (record: RouteItem) => { diff --git a/src/pages/model-routes/index.tsx b/src/pages/model-routes/index.tsx index 695ca2ff..6f63398e 100644 --- a/src/pages/model-routes/index.tsx +++ b/src/pages/model-routes/index.tsx @@ -1,17 +1,19 @@ import { expandKeysAtom } from '@/atoms/clusters'; import { registerRouteConfigAtom } from '@/atoms/routes'; -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; -import SealTable from '@/components/seal-table'; -import TableContext from '@/components/seal-table/table-context'; -import { TableOrder } from '@/components/seal-table/types'; import { PageAction } from '@/config'; import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings'; import useExpandedRowKeys from '@/hooks/use-expanded-row-keys'; import useTableFetch from '@/hooks/use-table-fetch'; import useWatchList from '@/hooks/use-watch-list'; import APIAccessInfoModal from '@/pages/llmodels/components/api-access-info'; +import { + DeleteModal, + FilterBar, + IconFont, + Table as SealTable, + TableProvider +} from '@gpustack/core-ui'; +import { TableOrder } from '@gpustack/core-ui/lib/components/table/types'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { message } from 'antd'; @@ -291,7 +293,7 @@ const ModelRoutes: React.FC = () => { handleDeleteByBatch={handleDeleteBatch} handleClickPrimary={handleClickDropdown} > - { onChange: handlePageChange }} > - + = forwardRef( const imgPromises: Promise[] = []; for (let i = 0; i < items.length; i++) { - let item = items[i]; + const item = items[i]; if (item.kind === 'file' && item.type.indexOf('image') !== -1) { const file = item.getAsFile(); diff --git a/src/pages/playground/components/model-select.tsx b/src/pages/playground/components/model-select.tsx index 9b2ad921..1e49051e 100644 --- a/src/pages/playground/components/model-select.tsx +++ b/src/pages/playground/components/model-select.tsx @@ -1,4 +1,4 @@ -import SealSelect from '@/components/seal-form/seal-select'; +import { Select as SealSelect } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React from 'react'; diff --git a/src/pages/playground/components/multiple-chat/content-item.tsx b/src/pages/playground/components/multiple-chat/content-item.tsx index 7eba67b3..3d72b7c5 100644 --- a/src/pages/playground/components/multiple-chat/content-item.tsx +++ b/src/pages/playground/components/multiple-chat/content-item.tsx @@ -1,5 +1,5 @@ -import IconFont from '@/components/icon-font'; import { StopOutlined } from '@ant-design/icons'; +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button } from 'antd'; import React, { useMemo } from 'react'; diff --git a/src/pages/playground/components/multiple-chat/message-actions.tsx b/src/pages/playground/components/multiple-chat/message-actions.tsx index 7a02df88..5d49a33b 100644 --- a/src/pages/playground/components/multiple-chat/message-actions.tsx +++ b/src/pages/playground/components/multiple-chat/message-actions.tsx @@ -1,5 +1,3 @@ -import CopyButton from '@/components/copy-button'; -import UploadAudio from '@/components/upload-audio'; import { audioTypeMap, convertFileToBase64, @@ -10,6 +8,7 @@ import { EditOutlined, MinusCircleOutlined } from '@ant-design/icons'; +import { CopyButton, UploadAudio } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Tooltip } from 'antd'; import classNames from 'classnames'; diff --git a/src/pages/playground/components/multiple-chat/message-body.tsx b/src/pages/playground/components/multiple-chat/message-body.tsx index b823a071..64fb88bf 100644 --- a/src/pages/playground/components/multiple-chat/message-body.tsx +++ b/src/pages/playground/components/multiple-chat/message-body.tsx @@ -1,5 +1,4 @@ -import SimpleAudio from '@/components/audio-player/simple-audio'; -import FullMarkdown from '@/components/markdown-viewer/full-markdown'; +import { FullMarkdown, SimpleAudio } from '@gpustack/core-ui'; import { Input } from 'antd'; import classNames from 'classnames'; import _ from 'lodash'; @@ -78,7 +77,7 @@ const MessageBody: React.FC = forwardRef( const imgPromises: Promise[] = []; for (let i = 0; i < items.length; i++) { - let item = items[i]; + const item = items[i]; if (item.kind === 'file' && item.type.indexOf('image') !== -1) { const file = item.getAsFile(); diff --git a/src/pages/playground/components/multiple-chat/model-item.tsx b/src/pages/playground/components/multiple-chat/model-item.tsx index 821dd594..1f85df17 100644 --- a/src/pages/playground/components/multiple-chat/model-item.tsx +++ b/src/pages/playground/components/multiple-chat/model-item.tsx @@ -1,13 +1,15 @@ -import AutoTooltip from '@/components/auto-tooltip'; -import IconFont from '@/components/icon-font'; -import OverlayScroller from '@/components/overlay-scroller'; -import BaseSelect from '@/components/seal-form/base/select'; import { ClearOutlined, DeleteOutlined, MoreOutlined, SettingOutlined } from '@ant-design/icons'; +import { + AutoTooltip, + BaseSelect, + IconFont, + OverlayScroller +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Checkbox, Dropdown, Popover, Spin } from 'antd'; import _ from 'lodash'; @@ -38,7 +40,6 @@ import ReferenceParams from '../reference-params'; import ViewCommonCode from '../view-common-code'; import MessageContent from './message-content'; import SystemMessage from './system-message'; - interface ModelItemProps { model: string; modelList: ModelSelectionItem[]; diff --git a/src/pages/playground/components/multiple-chat/think-content.tsx b/src/pages/playground/components/multiple-chat/think-content.tsx index 095b4ba4..4ee34e9f 100644 --- a/src/pages/playground/components/multiple-chat/think-content.tsx +++ b/src/pages/playground/components/multiple-chat/think-content.tsx @@ -1,4 +1,4 @@ -import FullMarkdown from '@/components/markdown-viewer/full-markdown'; +import { FullMarkdown } from '@gpustack/core-ui'; import React from 'react'; import '../../style/think-content.less'; diff --git a/src/pages/playground/components/multiple-chat/think-parser.ts b/src/pages/playground/components/multiple-chat/think-parser.ts index 00fa84fb..9704d5cf 100644 --- a/src/pages/playground/components/multiple-chat/think-parser.ts +++ b/src/pages/playground/components/multiple-chat/think-parser.ts @@ -13,8 +13,8 @@ class ThinkParser { parse(chunk: string) { while (this.lastCheckedIndex < chunk.length) { - let startIndex = chunk.indexOf('', this.lastCheckedIndex); - let endIndex = chunk.indexOf('', this.lastCheckedIndex); + const startIndex = chunk.indexOf('', this.lastCheckedIndex); + const endIndex = chunk.indexOf('', this.lastCheckedIndex); if (!this.collecting) { if (endIndex !== -1 && (startIndex === -1 || endIndex < startIndex)) { diff --git a/src/pages/playground/components/params-fields.tsx b/src/pages/playground/components/params-fields.tsx index 3e171b27..789d4395 100644 --- a/src/pages/playground/components/params-fields.tsx +++ b/src/pages/playground/components/params-fields.tsx @@ -1,4 +1,4 @@ -import FieldComponent from '@/components/seal-form/field-component'; +import { FieldComponent } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/playground/components/thumb-img.tsx b/src/pages/playground/components/thumb-img.tsx index 356037d1..1d447c5b 100644 --- a/src/pages/playground/components/thumb-img.tsx +++ b/src/pages/playground/components/thumb-img.tsx @@ -1,4 +1,4 @@ -import SingleImage from '@/components/auto-image/single-image'; +import { SingleImage } from '@gpustack/core-ui'; import { Col, Row } from 'antd'; import _ from 'lodash'; import React, { useCallback, useMemo } from 'react'; diff --git a/src/pages/playground/components/view-code-buttons.tsx b/src/pages/playground/components/view-code-buttons.tsx index dd82c13a..b12a4cec 100644 --- a/src/pages/playground/components/view-code-buttons.tsx +++ b/src/pages/playground/components/view-code-buttons.tsx @@ -1,7 +1,7 @@ +import { IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Space } from 'antd'; import React from 'react'; -import IconFont from '../../../components/icon-font'; const ViewCodeButtons: React.FC<{ handleViewCode: () => void; diff --git a/src/pages/playground/components/view-common-code.tsx b/src/pages/playground/components/view-common-code.tsx index a70ef318..96d28887 100644 --- a/src/pages/playground/components/view-common-code.tsx +++ b/src/pages/playground/components/view-common-code.tsx @@ -1,8 +1,8 @@ import { BulbOutlined } from '@ant-design/icons'; +import { CommandViewer } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Modal } from 'antd'; import React, { useEffect, useState } from 'react'; -import CommandViewer from '../../_components/command-viewer'; type ViewModalProps = { title?: string; diff --git a/src/pages/playground/embedding/forms/advance-config.tsx b/src/pages/playground/embedding/forms/advance-config.tsx index 27872db0..d1368223 100644 --- a/src/pages/playground/embedding/forms/advance-config.tsx +++ b/src/pages/playground/embedding/forms/advance-config.tsx @@ -1,4 +1,4 @@ -import SealInputNumber from '@/components/seal-form/input-number'; +import { InputNumber as CInputNumber } from '@gpustack/core-ui'; import { Form } from 'antd'; import _ from 'lodash'; import React from 'react'; @@ -11,11 +11,11 @@ const AdvanceConfig: React.FC = () => { <> {modelMeta?.n_ctx && modelMeta?.n_slot && ( - + > )} diff --git a/src/pages/playground/embedding/page.tsx b/src/pages/playground/embedding/page.tsx index e4d0fb56..f864aebd 100644 --- a/src/pages/playground/embedding/page.tsx +++ b/src/pages/playground/embedding/page.tsx @@ -1,17 +1,19 @@ -import AlertInfo from '@/components/alert-info'; -import ScatterChart from '@/components/echarts/scatter'; -import HighlightCode from '@/components/highlight-code'; -import IconFont from '@/components/icon-font'; -import SealInputNumber from '@/components/seal-form/input-number'; import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useRequestToken from '@/hooks/use-request-token'; -import ResizeContainer from '@/pages/_components/terminal-tabs/resize-container'; import { ClearOutlined, PlusOutlined, QuestionCircleOutlined, SendOutlined } from '@ant-design/icons'; +import { + AlertInfo, + InputNumber as CInputNumber, + HighlightCode, + IconFont, + ResizeContainer, + ScatterChart +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { Button, Checkbox, Form, Segmented, Spin, Tabs, Tooltip } from 'antd'; @@ -406,11 +408,11 @@ const GroundEmbedding: React.FC = forwardRef((props, ref) => { if (modelMeta?.n_ctx && modelMeta?.n_slot) { return ( - + > ); } diff --git a/src/pages/playground/hooks/use-add-image.tsx b/src/pages/playground/hooks/use-add-image.tsx index 8ab58d0c..1afea8fb 100644 --- a/src/pages/playground/hooks/use-add-image.tsx +++ b/src/pages/playground/hooks/use-add-image.tsx @@ -1,10 +1,10 @@ -import DropDownActions from '@/components/drop-down-actions'; import { DeleteOutlined, LinkOutlined, PictureOutlined, UploadOutlined } from '@ant-design/icons'; +import { DropdownActions } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Input, Tooltip } from 'antd'; import { useRef, useState } from 'react'; @@ -131,7 +131,7 @@ const useAddImage = (options: { ) : null; const UploadImageButton = ( - - + ); return { diff --git a/src/pages/playground/hooks/use-text-image.ts b/src/pages/playground/hooks/use-text-image.ts index 58cd3d96..ec109b73 100644 --- a/src/pages/playground/hooks/use-text-image.ts +++ b/src/pages/playground/hooks/use-text-image.ts @@ -54,7 +54,7 @@ export default function useTextImage(props: any) { }; const setImageSize = (parameters: any) => { - let size: Record = { + const size: Record = { span: 12 }; if (parameters.n === 1) { @@ -102,7 +102,7 @@ export default function useTextImage(props: any) { _.toNumber(item) ); - let newImageList = Array(parameters.n) + const newImageList = Array(parameters.n) .fill({}) .map((item, index: number) => { return { diff --git a/src/pages/playground/images/create.tsx b/src/pages/playground/images/create.tsx index d76972a2..05218d8c 100644 --- a/src/pages/playground/images/create.tsx +++ b/src/pages/playground/images/create.tsx @@ -1,10 +1,9 @@ import { setRouteCache } from '@/atoms/route-cache'; -import AlertInfo from '@/components/alert-info'; -import IconFont from '@/components/icon-font'; import routeCachekey from '@/config/route-cachekey'; import ThumbImg from '@/pages/playground/components/thumb-img'; import { generateRandomNumber } from '@/utils'; import { FileImageOutlined } from '@ant-design/icons'; +import { AlertInfo, IconFont } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Tooltip } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/playground/images/edit.tsx b/src/pages/playground/images/edit.tsx index 24b1853b..7641c087 100644 --- a/src/pages/playground/images/edit.tsx +++ b/src/pages/playground/images/edit.tsx @@ -1,12 +1,14 @@ import { setRouteCache } from '@/atoms/route-cache'; -import AlertInfo from '@/components/alert-info'; -import SingleImage from '@/components/auto-image/single-image'; -import IconFont from '@/components/icon-font'; -import CanvasImageEditor from '@/components/image-editor'; -import { processImage } from '@/components/image-editor/extract-image-colors'; import routeCachekey from '@/config/route-cachekey'; import UploadImg from '@/pages/playground/components/upload-img'; import { base64ToFile, generateRandomNumber } from '@/utils'; +import { + AlertInfo, + ImageEditor as CanvasImageEditor, + IconFont, + SingleImage +} from '@gpustack/core-ui'; +import { processImage } from '@gpustack/core-ui/lib/components/image-editor/extract-image-colors'; import { useIntl } from '@umijs/max'; import { Divider } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/playground/images/forms/index.tsx b/src/pages/playground/images/forms/index.tsx index b49f81b2..0340d72b 100644 --- a/src/pages/playground/images/forms/index.tsx +++ b/src/pages/playground/images/forms/index.tsx @@ -1,5 +1,4 @@ -import CheckboxField from '@/components/seal-form/checkbox-field'; -import SealInputNumber from '@/components/seal-form/input-number'; +import { InputNumber as CInputNumber, CheckboxField } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React, { forwardRef, useEffect, useImperativeHandle } from 'react'; @@ -99,10 +98,10 @@ const ParamsSettings: React.FC = forwardRef( > - + > { <> {modelMeta?.n_ctx && modelMeta?.n_slot && ( - + > )} diff --git a/src/pages/playground/rerank/page.tsx b/src/pages/playground/rerank/page.tsx index ed4840de..4da9a6b1 100644 --- a/src/pages/playground/rerank/page.tsx +++ b/src/pages/playground/rerank/page.tsx @@ -1,4 +1,3 @@ -import AlertInfo from '@/components/alert-info'; import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useRequestToken from '@/hooks/use-request-token'; import { @@ -7,6 +6,7 @@ import { QuestionCircleOutlined, SendOutlined } from '@ant-design/icons'; +import { AlertInfo } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Checkbox, Input, Spin, Tag, Tooltip, Typography } from 'antd'; import _ from 'lodash'; diff --git a/src/pages/playground/speech/forms/stt-form.tsx b/src/pages/playground/speech/forms/stt-form.tsx index dacba76f..2d02c7d8 100644 --- a/src/pages/playground/speech/forms/stt-form.tsx +++ b/src/pages/playground/speech/forms/stt-form.tsx @@ -1,5 +1,4 @@ -import CheckboxField from '@/components/seal-form/checkbox-field'; -import SealSelect from '@/components/seal-form/seal-select'; +import { CheckboxField, Select as SealSelect } from '@gpustack/core-ui'; import { useIntl, useSearchParams } from '@umijs/max'; import { Form } from 'antd'; import React, { diff --git a/src/pages/playground/speech/forms/tts-advance.tsx b/src/pages/playground/speech/forms/tts-advance.tsx index 6d68cef0..bd36b2a3 100644 --- a/src/pages/playground/speech/forms/tts-advance.tsx +++ b/src/pages/playground/speech/forms/tts-advance.tsx @@ -1,10 +1,12 @@ -import CheckboxField from '@/components/seal-form/checkbox-field'; -import InputNumber from '@/components/seal-form/input-number'; -import SealInput from '@/components/seal-form/seal-input'; -import UploadAudio from '@/components/upload-audio'; import useAppUtils from '@/hooks/use-app-utils'; import { convertFileToBase64 } from '@/utils/load-audio-file'; import { CloseCircleFilled } from '@ant-design/icons'; +import { + CheckboxField, + Input as CInput, + InputNumber, + UploadAudio +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import React, { useEffect } from 'react'; @@ -110,14 +112,14 @@ const TTSAdvanceConfig: React.FC = () => { } ]} > - + > { getValueProps={(value) => ({ value: fileName ? fileName : value })} dependencies={['task_type']} > - { id: 'playground.params.refAudio.tips' })} label={intl.formatMessage({ id: 'playground.params.refAudio' })} - > + > { dependencies={['task_type', 'x_vector_only_mode']} rules={[atLeastOneValidator('x_vector_only_mode')]} > - + > { } ]} > - + > name="new_password" @@ -76,12 +75,12 @@ const Profile: React.FC = () => { } ]} > - + > { }) ]} > - { record.resolved_paths?.[0] ); - let name = _.toLower( + const name = _.toLower( _.split( record.huggingface_repo_id || record.ollama_library_model_name || diff --git a/src/pages/resources/components/script-install.tsx b/src/pages/resources/components/script-install.tsx index 28a4cdcb..28f758e7 100644 --- a/src/pages/resources/components/script-install.tsx +++ b/src/pages/resources/components/script-install.tsx @@ -1,4 +1,4 @@ -import HighlightCode from '@/components/highlight-code'; +import { HighlightCode } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import React, { useMemo } from 'react'; import { addWorkerGuide } from '../config'; diff --git a/src/pages/resources/components/update-labels.tsx b/src/pages/resources/components/update-labels.tsx index de2f0aca..30ae4c12 100644 --- a/src/pages/resources/components/update-labels.tsx +++ b/src/pages/resources/components/update-labels.tsx @@ -1,7 +1,4 @@ -import LabelSelector from '@/components/label-selector'; -import ModalFooter from '@/components/modal-footer'; -import ScrollerModal from '@/components/scroller-modal'; -import SealInput from '@/components/seal-form/seal-input'; +import { LabelSelector, ModalFooter, ScrollerModal } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -66,7 +63,7 @@ const UpdateLabels: React.FC = (props) => { }} > name="name"> - - + > ); }; diff --git a/src/pages/resources/hooks/use-worker-columns.tsx b/src/pages/resources/hooks/use-worker-columns.tsx index d88a1ac6..c25671ae 100644 --- a/src/pages/resources/hooks/use-worker-columns.tsx +++ b/src/pages/resources/hooks/use-worker-columns.tsx @@ -1,14 +1,6 @@ import { systemConfigAtom } from '@/atoms/system'; import { GPUStackVersionAtom } from '@/atoms/user'; -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; -import IconFont from '@/components/icon-font'; -import LabelsCell from '@/components/label-cell'; -import ProgressBar from '@/components/progress-bar'; -import InfoColumn from '@/components/simple-table/info-column'; -import StatusTag from '@/components/status-tag'; import { tableSorter } from '@/config/settings'; -import GrafanaIcon from '@/pages/_components/grafana-icon'; import { convertFileSize } from '@/utils'; import { DeleteOutlined, @@ -18,6 +10,16 @@ import { SafetyOutlined, ToolOutlined } from '@ant-design/icons'; +import { + AutoTooltip, + DropdownButtons, + GrafanaIcon, + IconFont, + InfoColumn, + LabelCell, + ProgressBar, + StatusTag +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tooltip } from 'antd'; import { ColumnsType } from 'antd/lib/table'; @@ -29,7 +31,6 @@ import semverGt from 'semver/functions/gt'; import { status, WorkerStatusMap, WorkerStatusMapValue } from '../config'; import { Filesystem, GPUDeviceItem, ListItem } from '../config/types'; import workerCss from '../styles/worker.less'; - const ActionList = [ { label: 'common.button.edit', key: 'edit', icon: }, { @@ -400,7 +401,7 @@ const useWorkerColumns = ({ title: intl.formatMessage({ id: 'resources.table.labels' }), dataIndex: 'labels', width: 200, - render: (_, record) => + render: (_, record) => }, { title: intl.formatMessage({ id: 'clusters.title' }), diff --git a/src/pages/resources/hooks/use-worker-maintenance.tsx b/src/pages/resources/hooks/use-worker-maintenance.tsx index e743fdfe..5014cb78 100644 --- a/src/pages/resources/hooks/use-worker-maintenance.tsx +++ b/src/pages/resources/hooks/use-worker-maintenance.tsx @@ -1,7 +1,8 @@ -import ModalFooter from '@/components/modal-footer'; -import ScrollerModal from '@/components/scroller-modal'; -import SealInput from '@/components/seal-form/seal-input'; -import SealTextArea from '@/components/seal-form/seal-textarea'; +import { + ModalFooter, + ScrollerModal, + Textarea as SealTextArea +} from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form, message } from 'antd'; import React from 'react'; @@ -90,7 +91,7 @@ const useWorkerMaintenance = ({ fetchData }: { fetchData: () => void }) => { }} > - = ({ } ]} > - + > name="full_name" rules={[{ required: false }]}> - + >
    @@ -150,11 +152,11 @@ const AddModal: React.FC = ({ } ]} > - + > diff --git a/src/pages/users/hooks/use-users-columns.tsx b/src/pages/users/hooks/use-users-columns.tsx index 1c9d303d..1f15510c 100644 --- a/src/pages/users/hooks/use-users-columns.tsx +++ b/src/pages/users/hooks/use-users-columns.tsx @@ -1,9 +1,7 @@ // columns.ts -import AutoTooltip from '@/components/auto-tooltip'; -import DropdownButtons from '@/components/drop-down-buttons'; -import IconFont from '@/components/icon-font'; -import icons from '@/components/icon-font/icons'; import { tableSorter } from '@/config/settings'; +import { AutoTooltip, DropdownButtons, IconFont } from '@gpustack/core-ui'; +import icons from '@gpustack/core-ui/lib/components/icon-font/icons'; import { useIntl, useModel } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { Tag } from 'antd'; @@ -11,7 +9,6 @@ import { ColumnsType } from 'antd/lib/table'; import dayjs from 'dayjs'; import { useMemo } from 'react'; import { ListItem } from '../config/types'; - interface ColumnsHookProps { handleSelect: (val: string, record: ListItem) => void; sortOrder: string[]; diff --git a/src/pages/users/index.tsx b/src/pages/users/index.tsx index 648e0f99..db966a16 100644 --- a/src/pages/users/index.tsx +++ b/src/pages/users/index.tsx @@ -1,10 +1,8 @@ -import DeleteModal from '@/components/delete-modal'; -import IconFont from '@/components/icon-font'; -import { FilterBar } from '@/components/page-tools'; import { PageAction } from '@/config'; import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings'; import type { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; +import { DeleteModal, FilterBar, IconFont } from '@gpustack/core-ui'; import { useIntl, useModel } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { ConfigProvider, message, Table } from 'antd'; diff --git a/tsconfig.json b/tsconfig.json index f00d0f9c..93ab3233 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,15 +17,22 @@ "paths": { "@/*": ["./src/*"], "@@/*": ["./src/.umi/*"], - "@@test/*": ["./src/.umi-test/*"] + "@@test/*": ["./src/.umi-test/*"], + "@gpustack/core-ui": ["../core-ui/src/index.ts"], + "@gpustack/core-ui/*": ["../core-ui/src/*"], + "@gpustack/core-ui/hooks": ["../core-ui/src/lib/hooks"], + "@gpustack/core-ui/utils": ["../core-ui/src/lib/utils"], + "@gpustack/core-ui/types": ["../core-ui/src/lib/types"], + "@gpustack/core-ui/components": ["../core-ui/src/lib/components"], + "@gpustack/core-ui/lib/*": ["../core-ui/src/lib/*"] } }, "include": [ "./**/*.d.ts", "./**/*.ts", "./**/*.tsx", - "src/components/logs-viewer/parse-worker.ts", - "src/components/image-editor/invert-worker.ts", - "src/components/image-editor/offscreen-worker.ts" + "@gpustack/core-ui/lib/components/logs-viewer/parse-worker.ts", + "@gpustack/core-ui/lib/components/image-editor/invert-worker.ts", + "@gpustack/core-ui/lib/components/image-editor/offscreen-worker.ts" ] }