fix: usage chart y axis ticks, add esc hint for drawer
This commit is contained in:
@@ -18,6 +18,7 @@ const Chart: React.FC<{
|
|||||||
const chart = useRef<echarts.EChartsType>();
|
const chart = useRef<echarts.EChartsType>();
|
||||||
const resizeable = useRef(false);
|
const resizeable = useRef(false);
|
||||||
const resizeObserver = useRef<ResizeObserver>();
|
const resizeObserver = useRef<ResizeObserver>();
|
||||||
|
const finished = useRef(false);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => {
|
useImperativeHandle(ref, () => {
|
||||||
return {
|
return {
|
||||||
@@ -49,7 +50,7 @@ const Chart: React.FC<{
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleOnFinished = () => {
|
const handleOnFinished = () => {
|
||||||
if (!chart.current) return;
|
if (!chart.current || finished.current) return;
|
||||||
|
|
||||||
const currentChart = chart.current;
|
const currentChart = chart.current;
|
||||||
const optionsYAxis = currentChart.getOption()?.yAxis;
|
const optionsYAxis = currentChart.getOption()?.yAxis;
|
||||||
@@ -75,22 +76,32 @@ const Chart: React.FC<{
|
|||||||
const ticksList = axes.map((axis) => axis.scale.getTicks());
|
const ticksList = axes.map((axis) => axis.scale.getTicks());
|
||||||
const counts = ticksList.map((t) => t.length);
|
const counts = ticksList.map((t) => t.length);
|
||||||
|
|
||||||
if (counts[0] === counts[1]) return;
|
|
||||||
|
|
||||||
const unifiedCount = Math.max(counts[0], counts[1]);
|
const unifiedCount = Math.max(counts[0], counts[1]);
|
||||||
|
|
||||||
const newMax0 = intervals[0] * (unifiedCount - 1);
|
const newMax0 = intervals[0] * (unifiedCount - 1);
|
||||||
const newMax1 = intervals[1] * (unifiedCount - 1);
|
const newMax1 = intervals[1] * (unifiedCount - 1);
|
||||||
|
|
||||||
|
// get yaxis max value
|
||||||
|
const maxValue0 = Math.max();
|
||||||
|
const maxValue1 = yAxisModels[1].get('max');
|
||||||
|
|
||||||
|
// if newMax0 equal to maxValue0, and newMax1 equal to maxValue1, do not update yAxis
|
||||||
|
if (counts[0] === counts[1]) return;
|
||||||
|
|
||||||
const yAxis: any[] = [{}, {}];
|
const yAxis: any[] = [{}, {}];
|
||||||
|
|
||||||
if (counts[0] < unifiedCount) {
|
if (counts[0] < unifiedCount) {
|
||||||
yAxis[0].max = newMax0;
|
yAxis[0].max = newMax0;
|
||||||
|
yAxis[0].interval = intervals[0];
|
||||||
|
yAxis[0].splitNumber = unifiedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counts[1] < unifiedCount) {
|
if (counts[1] < unifiedCount) {
|
||||||
yAxis[1].max = newMax1;
|
yAxis[1].max = newMax1;
|
||||||
|
yAxis[1].interval = intervals[1];
|
||||||
|
yAxis[1].splitNumber = unifiedCount;
|
||||||
}
|
}
|
||||||
|
finished.current = true;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
currentChart.setOption({
|
currentChart.setOption({
|
||||||
@@ -112,6 +123,7 @@ const Chart: React.FC<{
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
resizeable.current = false;
|
resizeable.current = false;
|
||||||
|
finished.current = false;
|
||||||
resize();
|
resize();
|
||||||
setOption(options);
|
setOption(options);
|
||||||
resizeable.current = true;
|
resizeable.current = true;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { useEscHint } from '@/hooks/use-esc-hint';
|
||||||
|
import { Drawer, type DrawerProps } from 'antd';
|
||||||
|
|
||||||
|
const ScrollerModal = (props: DrawerProps) => {
|
||||||
|
const { EscHint } = useEscHint({
|
||||||
|
enabled: !props.keyboard && props.open
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Drawer {...props}>
|
||||||
|
{props.children}
|
||||||
|
{EscHint}
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ScrollerModal;
|
||||||
@@ -27,7 +27,8 @@ const KeybindingsMap = {
|
|||||||
NEW3: ['Ctrl+3', 'Meta+3'],
|
NEW3: ['Ctrl+3', 'Meta+3'],
|
||||||
NEW4: ['Ctrl+4', 'Meta+4'],
|
NEW4: ['Ctrl+4', 'Meta+4'],
|
||||||
FOCUS: ['/', '/'],
|
FOCUS: ['/', '/'],
|
||||||
ADD: ['Alt+Ctrl+Enter', 'Alt+Meta+Enter']
|
ADD: ['Alt+Ctrl+Enter', 'Alt+Meta+Enter'],
|
||||||
|
ESC: ['Esc', 'Esc']
|
||||||
};
|
};
|
||||||
|
|
||||||
type KeyBindingType = keyof typeof KeybindingsMap;
|
type KeyBindingType = keyof typeof KeybindingsMap;
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export default {
|
|||||||
},
|
},
|
||||||
Tabs: {
|
Tabs: {
|
||||||
titleFontSizeLG: 14
|
titleFontSizeLG: 14
|
||||||
// cardBg: '#1D1E20'
|
},
|
||||||
|
DatePicker: {
|
||||||
|
fontSizeLG: 14
|
||||||
},
|
},
|
||||||
Menu: {
|
Menu: {
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ html {
|
|||||||
--ant-color-border: #d9d9d9;
|
--ant-color-border: #d9d9d9;
|
||||||
--ant-line-type: solid;
|
--ant-line-type: solid;
|
||||||
--ant-line-width: 1px;
|
--ant-line-width: 1px;
|
||||||
|
--color-esc-hint-bg: rgba(0, 0, 0, 75%);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme='realDark'] {
|
html[data-theme='realDark'] {
|
||||||
@@ -99,6 +100,7 @@ html[data-theme='realDark'] {
|
|||||||
--color-modal-content-bg: #1f1f1f;
|
--color-modal-content-bg: #1f1f1f;
|
||||||
--color-modal-box-shadow: none;
|
--color-modal-box-shadow: none;
|
||||||
--color-spotlight-bg: #3e3e3e;
|
--color-spotlight-bg: #3e3e3e;
|
||||||
|
--color-esc-hint-bg: rgba(150, 150, 150, 75%);
|
||||||
|
|
||||||
background: #141414;
|
background: #141414;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import HotKeys from '@/config/hotkeys';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import { throttle } from 'lodash';
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css, token }) => ({
|
||||||
|
hintOverlay: css`
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: var(--color-esc-hint-bg);
|
||||||
|
color: ${token.colorTextLightSolid};
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-radius: 4px;
|
||||||
|
z-index: 2000;
|
||||||
|
font-size: 14px;
|
||||||
|
pointer-events: none;
|
||||||
|
animation: fadeInOut 2s ease-in-out;
|
||||||
|
@keyframes fadeInOut {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}));
|
||||||
|
|
||||||
|
export function useEscHint(options?: {
|
||||||
|
enabled?: boolean;
|
||||||
|
message?: string;
|
||||||
|
throttleDelay?: number;
|
||||||
|
}) {
|
||||||
|
const { enabled = true, message, throttleDelay = 3000 } = options || {};
|
||||||
|
const intl = useIntl();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const timeoutRef = useRef<any>(null);
|
||||||
|
|
||||||
|
const showHintThrottled = useMemo(
|
||||||
|
() =>
|
||||||
|
throttle(
|
||||||
|
() => {
|
||||||
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
||||||
|
setVisible(true);
|
||||||
|
timeoutRef.current = setTimeout(() => setVisible(false), 2000);
|
||||||
|
},
|
||||||
|
throttleDelay,
|
||||||
|
{
|
||||||
|
leading: true,
|
||||||
|
trailing: false
|
||||||
|
}
|
||||||
|
),
|
||||||
|
[throttleDelay]
|
||||||
|
);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
HotKeys.ESC,
|
||||||
|
() => {
|
||||||
|
showHintThrottled();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: enabled
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
showHintThrottled.cancel();
|
||||||
|
};
|
||||||
|
}, [showHintThrottled]);
|
||||||
|
|
||||||
|
const EscHint = visible ? (
|
||||||
|
<div className={styles.hintOverlay}>
|
||||||
|
{message || intl.formatMessage({ id: 'common.tips.escape.disable' })}
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
return { EscHint };
|
||||||
|
}
|
||||||
@@ -247,5 +247,7 @@ export default {
|
|||||||
'common.appearance.theme': 'Theme',
|
'common.appearance.theme': 'Theme',
|
||||||
'common.page.wentwrong': 'Something went wrong.',
|
'common.page.wentwrong': 'Something went wrong.',
|
||||||
'common.page.refresh.tips':
|
'common.page.refresh.tips':
|
||||||
'Oops! Something went wrong. Try refreshing the page.'
|
'Oops! Something went wrong. Try refreshing the page.',
|
||||||
|
'common.tips.escape.disable':
|
||||||
|
'Click Cancel or the X at the top right to close.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -247,7 +247,9 @@ export default {
|
|||||||
'common.appearance.theme': 'Theme',
|
'common.appearance.theme': 'Theme',
|
||||||
'common.page.wentwrong': 'Something went wrong.',
|
'common.page.wentwrong': 'Something went wrong.',
|
||||||
'common.page.refresh.tips':
|
'common.page.refresh.tips':
|
||||||
'Oops! Something went wrong. Try refreshing the page.'
|
'Oops! Something went wrong. Try refreshing the page.',
|
||||||
|
'common.tips.escape.disable':
|
||||||
|
'Click Cancel or the X at the top right to close.'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -263,4 +265,5 @@ export default {
|
|||||||
// 10. 'common.appearance.theme': 'Theme',
|
// 10. 'common.appearance.theme': 'Theme',
|
||||||
// 11. 'common.page.wentwrong': 'Something went wrong.',
|
// 11. 'common.page.wentwrong': 'Something went wrong.',
|
||||||
// 12. 'common.page.refresh.tips': 'Oops! Something went wrong. Try refreshing the page.'
|
// 12. 'common.page.refresh.tips': 'Oops! Something went wrong. Try refreshing the page.'
|
||||||
|
// 13. 'common.tips.escape.disable': 'Click Cancel or the X at the top right to close.'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -245,9 +245,12 @@ export default {
|
|||||||
'common.button.forgotpassword': 'Забыли пароль?',
|
'common.button.forgotpassword': 'Забыли пароль?',
|
||||||
'common.appearance.theme': 'Тема',
|
'common.appearance.theme': 'Тема',
|
||||||
'common.page.wentwrong': 'Что-то пошло не так.',
|
'common.page.wentwrong': 'Что-то пошло не так.',
|
||||||
'common.page.refresh.tips': 'Упс! Что-то пошло не так. Попробуйте обновить страницу.'
|
'common.page.refresh.tips':
|
||||||
|
'Упс! Что-то пошло не так. Попробуйте обновить страницу.',
|
||||||
|
'common.tips.escape.disable':
|
||||||
|
'Click Cancel or the X at the top right to close.'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
|
// 1. 'common.tips.escape.disable': 'Click Cancel or the X at the top right to close.'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -241,5 +241,6 @@ export default {
|
|||||||
'common.button.forgotpassword': '忘记密码?',
|
'common.button.forgotpassword': '忘记密码?',
|
||||||
'common.appearance.theme': '主题',
|
'common.appearance.theme': '主题',
|
||||||
'common.page.wentwrong': '哎呀,出了点问题',
|
'common.page.wentwrong': '哎呀,出了点问题',
|
||||||
'common.page.refresh.tips': '出了点问题,试试刷新页面吧!'
|
'common.page.refresh.tips': '出了点问题,试试刷新页面吧!',
|
||||||
|
'common.tips.escape.disable': '请点击「取消」按钮或右上角 X 关闭窗口'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ const ActiveTable = () => {
|
|||||||
left={
|
left={
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
padding: '9px 0',
|
|
||||||
fontWeight: 'var(--font-weight-bold)'
|
fontWeight: 'var(--font-weight-bold)'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const FilterWrapper = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 0px;
|
||||||
.selection {
|
.selection {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -61,44 +61,48 @@ const UsageInner: FC<{ paddingRight: string }> = ({ paddingRight }) => {
|
|||||||
xl={16}
|
xl={16}
|
||||||
style={{ paddingRight: paddingRight }}
|
style={{ paddingRight: paddingRight }}
|
||||||
>
|
>
|
||||||
<TitleWrapper>
|
<div
|
||||||
{intl.formatMessage({ id: 'dashboard.usage' })}
|
style={{
|
||||||
</TitleWrapper>
|
display: 'flex',
|
||||||
<FilterWrapper>
|
justifyContent: 'space-between',
|
||||||
<div className="selection">
|
alignItems: 'center',
|
||||||
<DatePicker.RangePicker
|
marginBottom: 0
|
||||||
style={{ width: 240 }}
|
}}
|
||||||
></DatePicker.RangePicker>
|
>
|
||||||
<Select
|
<TitleWrapper>
|
||||||
mode="multiple"
|
{intl.formatMessage({ id: 'dashboard.usage' })}
|
||||||
maxTagCount={1}
|
</TitleWrapper>
|
||||||
placeholder={intl.formatMessage({
|
<FilterWrapper>
|
||||||
id: 'dashboard.usage.selectuser'
|
<Button
|
||||||
})}
|
type="text"
|
||||||
style={{ width: 160 }}
|
icon={<ExportOutlined />}
|
||||||
></Select>
|
onClick={handleExport}
|
||||||
<Select
|
>
|
||||||
mode="multiple"
|
{intl.formatMessage({ id: 'common.button.export' })}
|
||||||
maxTagCount={1}
|
</Button>
|
||||||
placeholder={intl.formatMessage({
|
<div className="selection">
|
||||||
id: 'dashboard.usage.selectmodel'
|
<DatePicker.RangePicker
|
||||||
})}
|
style={{ width: 240 }}
|
||||||
style={{ width: 160 }}
|
></DatePicker.RangePicker>
|
||||||
></Select>
|
<Select
|
||||||
</div>
|
mode="multiple"
|
||||||
<Button
|
maxTagCount={1}
|
||||||
type="text"
|
placeholder={intl.formatMessage({
|
||||||
icon={<ExportOutlined />}
|
id: 'dashboard.usage.selectuser'
|
||||||
onClick={handleExport}
|
})}
|
||||||
>
|
style={{ width: 160 }}
|
||||||
{intl.formatMessage({ id: 'common.button.export' })}
|
></Select>
|
||||||
</Button>
|
<Select
|
||||||
</FilterWrapper>
|
mode="multiple"
|
||||||
{/* <SimpleCard
|
maxTagCount={1}
|
||||||
dataList={dataList}
|
placeholder={intl.formatMessage({
|
||||||
height={80}
|
id: 'dashboard.usage.selectmodel'
|
||||||
bordered={true}
|
})}
|
||||||
></SimpleCard> */}
|
style={{ width: 160 }}
|
||||||
|
></Select>
|
||||||
|
</div>
|
||||||
|
</FilterWrapper>
|
||||||
|
</div>
|
||||||
<RequestTokenInner
|
<RequestTokenInner
|
||||||
requestData={requestTokenData.requestData}
|
requestData={requestTokenData.requestData}
|
||||||
xAxisData={requestTokenData.xAxisData}
|
xAxisData={requestTokenData.xAxisData}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const TopUser: React.FC<TopUserProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CardWrapper>
|
<CardWrapper>
|
||||||
<HBar seriesData={userData} xAxisData={topUserList} height={496}></HBar>
|
<HBar seriesData={userData} xAxisData={topUserList} height={440}></HBar>
|
||||||
</CardWrapper>
|
</CardWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
|
import GSDrawer from '@/components/scroller-modal/gs-drawer';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
||||||
import { CloseOutlined } from '@ant-design/icons';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Drawer } from 'antd';
|
import { Button } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@@ -500,7 +501,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<GSDrawer
|
||||||
title={
|
title={
|
||||||
<div className="flex-between flex-center">
|
<div className="flex-between flex-center">
|
||||||
<span
|
<span
|
||||||
@@ -613,7 +614,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
</ColumnWrapper>
|
</ColumnWrapper>
|
||||||
</FormWrapper>
|
</FormWrapper>
|
||||||
</FormContext.Provider>
|
</FormContext.Provider>
|
||||||
</Drawer>
|
</GSDrawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
|
import GSDrawer from '@/components/scroller-modal/gs-drawer';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { CloseOutlined } from '@ant-design/icons';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Drawer } from 'antd';
|
import { Button } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@@ -14,6 +15,8 @@ import {
|
|||||||
import { FormContext } from '../config/form-context';
|
import { FormContext } from '../config/form-context';
|
||||||
import { FormData, SourceType } from '../config/types';
|
import { FormData, SourceType } from '../config/types';
|
||||||
import {
|
import {
|
||||||
|
MessageStatus,
|
||||||
|
WarningStausOptions,
|
||||||
checkOnlyAscendNPU,
|
checkOnlyAscendNPU,
|
||||||
useCheckCompatibility,
|
useCheckCompatibility,
|
||||||
useSelectModel
|
useSelectModel
|
||||||
@@ -106,6 +109,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
setWarningStatus,
|
setWarningStatus,
|
||||||
handleBackendChangeBefore,
|
handleBackendChangeBefore,
|
||||||
cancelEvaluate,
|
cancelEvaluate,
|
||||||
|
unlockWarningStatus,
|
||||||
handleOnValuesChange: handleOnValuesChangeBefore,
|
handleOnValuesChange: handleOnValuesChangeBefore,
|
||||||
handleEvaluateOnChange,
|
handleEvaluateOnChange,
|
||||||
warningStatus,
|
warningStatus,
|
||||||
@@ -141,7 +145,8 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param state target to distinguish the evaluate state
|
* @param state target to distinguish the evaluate state, current evaluate state
|
||||||
|
* can be 'model', 'file' or 'form'.
|
||||||
*/
|
*/
|
||||||
const setEvaluteState = (state: EvaluateProccessType) => {
|
const setEvaluteState = (state: EvaluateProccessType) => {
|
||||||
evaluateStateRef.current.state = state;
|
evaluateStateRef.current.state = state;
|
||||||
@@ -203,6 +208,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (item.fakeName) {
|
if (item.fakeName) {
|
||||||
|
unlockWarningStatus();
|
||||||
const currentModelId = requestModelIdRef.current;
|
const currentModelId = requestModelIdRef.current;
|
||||||
setEvaluteState(EvaluateProccess.file);
|
setEvaluteState(EvaluateProccess.file);
|
||||||
const evaluateRes = await handleEvaluateOnChange?.({
|
const evaluateRes = await handleEvaluateOnChange?.({
|
||||||
@@ -245,7 +251,10 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
* evaluate: true means select a model file from the evaluate result
|
* evaluate: true means select a model file from the evaluate result
|
||||||
*/
|
*/
|
||||||
updateRequestModelId();
|
updateRequestModelId();
|
||||||
|
|
||||||
|
// If the evaluate is false, it means that the user selects a new model or the first time to open the modal.
|
||||||
if (!evaluate) {
|
if (!evaluate) {
|
||||||
|
unlockWarningStatus();
|
||||||
setEvaluteState(EvaluateProccess.model);
|
setEvaluteState(EvaluateProccess.model);
|
||||||
setSelectedModel(item);
|
setSelectedModel(item);
|
||||||
form.current?.form?.resetFields(resetFieldsByModel);
|
form.current?.form?.resetFields(resetFieldsByModel);
|
||||||
@@ -260,8 +269,8 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
setIsGGUF(false);
|
setIsGGUF(false);
|
||||||
const modelInfo = onSelectModel(item, props.source);
|
const modelInfo = onSelectModel(item, props.source);
|
||||||
if (
|
if (
|
||||||
!isHolderRef.current.model &&
|
evaluateStateRef.current.state === EvaluateProccess.model &&
|
||||||
evaluateStateRef.current.state === EvaluateProccess.model
|
item.evaluateResult
|
||||||
) {
|
) {
|
||||||
handleShowCompatibleAlert(item.evaluateResult);
|
handleShowCompatibleAlert(item.evaluateResult);
|
||||||
form.current?.setFieldsValue?.({
|
form.current?.setFieldsValue?.({
|
||||||
@@ -365,17 +374,20 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
return warningStatus.show && warningStatus.type !== 'success';
|
return warningStatus.show && warningStatus.type !== 'success';
|
||||||
}, [warningStatus.show, warningStatus.type]);
|
}, [warningStatus.show, warningStatus.type]);
|
||||||
|
|
||||||
const displayEvaluateStatus = (data: {
|
// This is only a placeholder for querying the model or file during the transition period.
|
||||||
show?: boolean;
|
const displayEvaluateStatus = (
|
||||||
flag: Record<string, boolean>;
|
params: MessageStatus,
|
||||||
}) => {
|
options?: WarningStausOptions
|
||||||
setIsHolderRef(data.flag);
|
) => {
|
||||||
setWarningStatus({
|
setWarningStatus(
|
||||||
show: isHolderRef.current.model || isHolderRef.current.file,
|
{
|
||||||
title: '',
|
show: params.show,
|
||||||
type: 'transition',
|
title: '',
|
||||||
message: intl.formatMessage({ id: 'models.form.evaluating' })
|
type: 'transition',
|
||||||
});
|
message: intl.formatMessage({ id: 'models.form.evaluating' })
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -395,7 +407,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
}, [open, props.gpuOptions.length]);
|
}, [open, props.gpuOptions.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<GSDrawer
|
||||||
title={
|
title={
|
||||||
<div className="flex-between flex-center">
|
<div className="flex-between flex-center">
|
||||||
<span>{title}</span>
|
<span>{title}</span>
|
||||||
@@ -435,6 +447,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
modelSource={props.source}
|
modelSource={props.source}
|
||||||
onSelectModel={handleOnSelectModel}
|
onSelectModel={handleOnSelectModel}
|
||||||
displayEvaluateStatus={displayEvaluateStatus}
|
displayEvaluateStatus={displayEvaluateStatus}
|
||||||
|
unlockWarningStatus={unlockWarningStatus}
|
||||||
gpuOptions={props.gpuOptions}
|
gpuOptions={props.gpuOptions}
|
||||||
></SearchModel>
|
></SearchModel>
|
||||||
</ColumnWrapper>
|
</ColumnWrapper>
|
||||||
@@ -535,7 +548,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
</FormWrapper>
|
</FormWrapper>
|
||||||
</FormContext.Provider>
|
</FormContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
</Drawer>
|
</GSDrawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ import React, {
|
|||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import 'simplebar-react/dist/simplebar.min.css';
|
import 'simplebar-react/dist/simplebar.min.css';
|
||||||
|
import styled from 'styled-components';
|
||||||
import {
|
import {
|
||||||
downloadModelFile,
|
downloadModelFile,
|
||||||
downloadModelScopeModelfile,
|
|
||||||
queryHuggingfaceModelDetail,
|
queryHuggingfaceModelDetail,
|
||||||
queryModelScopeModelDetail
|
queryModelScopeModelDetail
|
||||||
} from '../apis';
|
} from '../apis';
|
||||||
@@ -30,6 +30,41 @@ import { modelSourceMap } from '../config';
|
|||||||
import '../style/model-card.less';
|
import '../style/model-card.less';
|
||||||
import TitleWrapper from './title-wrapper';
|
import TitleWrapper from './title-wrapper';
|
||||||
|
|
||||||
|
const MkdTitle = styled.span`
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--ant-color-fill-tertiary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
height: 36px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const MarkDownTitle: React.FC<{
|
||||||
|
collapsed: boolean;
|
||||||
|
loading: boolean;
|
||||||
|
onCollapse: () => void;
|
||||||
|
}> = ({ collapsed, loading, onCollapse }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
return (
|
||||||
|
<MkdTitle onClick={onCollapse}>
|
||||||
|
<span>
|
||||||
|
<FileTextOutlined className="m-r-2 text-tertiary" />{' '}
|
||||||
|
{intl.formatMessage({ id: 'models.readme' })}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{collapsed ? (
|
||||||
|
<DownOutlined />
|
||||||
|
) : loading ? (
|
||||||
|
<Spin spinning={true} size="small"></Spin>
|
||||||
|
) : (
|
||||||
|
<RightOutlined />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</MkdTitle>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const ModelCard: React.FC<{
|
const ModelCard: React.FC<{
|
||||||
onCollapse: (flag: boolean) => void;
|
onCollapse: (flag: boolean) => void;
|
||||||
setIsGGUF: (flag: boolean) => void;
|
setIsGGUF: (flag: boolean) => void;
|
||||||
@@ -69,6 +104,7 @@ const ModelCard: React.FC<{
|
|||||||
return modelData?.ModelType?.[0];
|
return modelData?.ModelType?.[0];
|
||||||
}
|
}
|
||||||
}, [modelData, modelSource]);
|
}, [modelData, modelSource]);
|
||||||
|
|
||||||
const loadFile = useCallback(async (repo: string, sha: string) => {
|
const loadFile = useCallback(async (repo: string, sha: string) => {
|
||||||
try {
|
try {
|
||||||
axiosTokenRef.current?.abort?.();
|
axiosTokenRef.current?.abort?.();
|
||||||
@@ -95,27 +131,6 @@ const ModelCard: React.FC<{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadConfig = useCallback(async (repo: string, sha: string) => {
|
|
||||||
try {
|
|
||||||
loadConfigTokenRef.current?.abort?.();
|
|
||||||
loadConfigTokenRef.current = new AbortController();
|
|
||||||
const res = await downloadModelFile(
|
|
||||||
{
|
|
||||||
repo,
|
|
||||||
revision: sha,
|
|
||||||
path: 'config.json'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
signal: loadConfigTokenRef.current.signal
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return res || null;
|
|
||||||
} catch (error) {
|
|
||||||
console.log('error======', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const removeMetadata = useCallback((str: string) => {
|
const removeMetadata = useCallback((str: string) => {
|
||||||
let indexes = [];
|
let indexes = [];
|
||||||
let index = str.indexOf('---');
|
let index = str.indexOf('---');
|
||||||
@@ -165,23 +180,6 @@ const ModelCard: React.FC<{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadModelscopeModelConfig = useCallback(async (name: string) => {
|
|
||||||
try {
|
|
||||||
loadConfigJsonTokenRef.current?.abort?.();
|
|
||||||
loadConfigJsonTokenRef.current = new AbortController();
|
|
||||||
return await downloadModelScopeModelfile(
|
|
||||||
{
|
|
||||||
name: name
|
|
||||||
},
|
|
||||||
{
|
|
||||||
signal: loadConfigJsonTokenRef.current.token
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getModelScopeModelDetail = async () => {
|
const getModelScopeModelDetail = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await queryModelScopeModelDetail(
|
const data = await queryModelScopeModelDetail(
|
||||||
@@ -352,27 +350,25 @@ const ModelCard: React.FC<{
|
|||||||
overflow: 'hidden'
|
overflow: 'hidden'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="mkd-title" onClick={handleCollapse}>
|
<MarkDownTitle
|
||||||
<span>
|
onCollapse={handleCollapse}
|
||||||
<FileTextOutlined className="m-r-2 text-tertiary" />{' '}
|
collapsed={collapsed}
|
||||||
README.md
|
loading={loading}
|
||||||
</span>
|
></MarkDownTitle>
|
||||||
<span>
|
<Spin spinning={loading && collapsed}>
|
||||||
{collapsed ? <DownOutlined /> : <RightOutlined />}
|
<SimpleOverlay
|
||||||
</span>
|
style={{
|
||||||
</span>
|
paddingTop: collapsed ? 12 : 0,
|
||||||
<SimpleOverlay
|
maxHeight: collapsed ? 300 : 0
|
||||||
style={{
|
}}
|
||||||
paddingTop: collapsed ? 12 : 0,
|
>
|
||||||
maxHeight: collapsed ? 300 : 0
|
<MarkdownViewer
|
||||||
}}
|
generateImgLink={generateModeScopeImgLink}
|
||||||
>
|
content={readmeText}
|
||||||
<MarkdownViewer
|
theme="light"
|
||||||
generateImgLink={generateModeScopeImgLink}
|
></MarkdownViewer>
|
||||||
content={readmeText}
|
</SimpleOverlay>
|
||||||
theme="light"
|
</Spin>
|
||||||
></MarkdownViewer>
|
|
||||||
</SimpleOverlay>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ import {
|
|||||||
modelSourceMap
|
modelSourceMap
|
||||||
} from '../config';
|
} from '../config';
|
||||||
import { handleRecognizeAudioModel } from '../config/audio-catalog';
|
import { handleRecognizeAudioModel } from '../config/audio-catalog';
|
||||||
import { checkCurrentbackend } from '../hooks';
|
import {
|
||||||
|
MessageStatus,
|
||||||
|
WarningStausOptions,
|
||||||
|
checkCurrentbackend
|
||||||
|
} from '../hooks';
|
||||||
import SearchStyle from '../style/search-result.less';
|
import SearchStyle from '../style/search-result.less';
|
||||||
import SearchInput from './search-input';
|
import SearchInput from './search-input';
|
||||||
import SearchResult from './search-result';
|
import SearchResult from './search-result';
|
||||||
@@ -37,10 +41,11 @@ interface SearchInputProps {
|
|||||||
setLoadingModel?: (flag: boolean) => void;
|
setLoadingModel?: (flag: boolean) => void;
|
||||||
onSourceChange?: (source: string) => void;
|
onSourceChange?: (source: string) => void;
|
||||||
onSelectModel: (model: any, evaluate?: boolean) => void;
|
onSelectModel: (model: any, evaluate?: boolean) => void;
|
||||||
displayEvaluateStatus?: (data: {
|
unlockWarningStatus?: () => void;
|
||||||
show?: boolean;
|
displayEvaluateStatus?: (
|
||||||
flag: Record<string, boolean>;
|
data: MessageStatus,
|
||||||
}) => void;
|
options?: WarningStausOptions
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchModel: React.FC<SearchInputProps> = (props) => {
|
const SearchModel: React.FC<SearchInputProps> = (props) => {
|
||||||
@@ -52,7 +57,8 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
gpuOptions,
|
gpuOptions,
|
||||||
setLoadingModel,
|
setLoadingModel,
|
||||||
onSelectModel,
|
onSelectModel,
|
||||||
displayEvaluateStatus
|
displayEvaluateStatus,
|
||||||
|
unlockWarningStatus
|
||||||
} = props;
|
} = props;
|
||||||
const [dataSource, setDataSource] = useState<{
|
const [dataSource, setDataSource] = useState<{
|
||||||
repoOptions: any[];
|
repoOptions: any[];
|
||||||
@@ -296,19 +302,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
(item) => item.id === currentRef.current
|
(item) => item.id === currentRef.current
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* if item is GGUF, the evaluating would be do after selecting the model file, Or the evaluate status of model would be overrided the
|
|
||||||
* file evaluate status.
|
|
||||||
*/
|
|
||||||
if (currentItem && !currentItem.isGGUF) {
|
|
||||||
displayEvaluateStatus?.({
|
|
||||||
show: false,
|
|
||||||
flag: {
|
|
||||||
model: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentItem) {
|
if (currentItem) {
|
||||||
handleOnSelectModel(currentItem, true);
|
handleOnSelectModel(currentItem, true);
|
||||||
}
|
}
|
||||||
@@ -372,12 +365,18 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
networkError: false,
|
networkError: false,
|
||||||
sortType: sort
|
sortType: sort
|
||||||
});
|
});
|
||||||
displayEvaluateStatus?.({
|
|
||||||
show: true,
|
// It's a new request, so we need to reset the state
|
||||||
flag: {
|
unlockWarningStatus?.();
|
||||||
model: list.length > 0
|
displayEvaluateStatus?.(
|
||||||
|
{
|
||||||
|
show: list.length > 0,
|
||||||
|
message: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
override: true
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
handleOnSelectModel(list[0]);
|
handleOnSelectModel(list[0]);
|
||||||
setLoadingModel?.(false);
|
setLoadingModel?.(false);
|
||||||
|
|
||||||
@@ -393,9 +392,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
setLoadingModel?.(false);
|
setLoadingModel?.(false);
|
||||||
displayEvaluateStatus?.({
|
displayEvaluateStatus?.({
|
||||||
show: false,
|
show: false,
|
||||||
flag: {
|
message: ''
|
||||||
model: false
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
handleOnSelectModel({});
|
handleOnSelectModel({});
|
||||||
cacheRepoOptions.current = [];
|
cacheRepoOptions.current = [];
|
||||||
@@ -460,12 +457,17 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
repoOptions: currentList
|
repoOptions: currentList
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
displayEvaluateStatus?.({
|
unlockWarningStatus?.();
|
||||||
show: true,
|
// reset evaluate status
|
||||||
flag: {
|
displayEvaluateStatus?.(
|
||||||
model: true
|
{
|
||||||
|
show: true,
|
||||||
|
message: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
override: true
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
console.log('isEvaluating:', isEvaluating);
|
console.log('isEvaluating:', isEvaluating);
|
||||||
handleOnSelectModel(currentList[0]);
|
handleOnSelectModel(currentList[0]);
|
||||||
handleEvaluate(currentList);
|
handleEvaluate(currentList);
|
||||||
|
|||||||
@@ -128,4 +128,4 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(SearchResult);
|
export default SearchResult;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
|
import GSDrawer from '@/components/scroller-modal/gs-drawer';
|
||||||
import { CloseOutlined } from '@ant-design/icons';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Drawer } from 'antd';
|
import { Button } from 'antd';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import ColumnWrapper from '../components/column-wrapper';
|
import ColumnWrapper from '../components/column-wrapper';
|
||||||
@@ -125,7 +126,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
}, [open, source]);
|
}, [open, source]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<GSDrawer
|
||||||
title={
|
title={
|
||||||
<div className="flex-between flex-center">
|
<div className="flex-between flex-center">
|
||||||
<span
|
<span
|
||||||
@@ -248,7 +249,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
</ColumnWrapper>
|
</ColumnWrapper>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Drawer>
|
</GSDrawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
ListItem
|
ListItem
|
||||||
} from '../config/types';
|
} from '../config/types';
|
||||||
|
|
||||||
type MessageStatus = {
|
export type MessageStatus = {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
title?: string;
|
title?: string;
|
||||||
type?: Global.MessageType;
|
type?: Global.MessageType;
|
||||||
@@ -36,7 +36,7 @@ type MessageStatus = {
|
|||||||
evaluateResult?: EvaluateResult;
|
evaluateResult?: EvaluateResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
type WarningStausOptions = {
|
export type WarningStausOptions = {
|
||||||
lockAfterUpdate?: boolean;
|
lockAfterUpdate?: boolean;
|
||||||
override?: boolean;
|
override?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,16 +24,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mkd-title {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: var(--ant-color-fill-tertiary);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 10px;
|
|
||||||
height: 36px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-wrapper {
|
.card-wrapper {
|
||||||
|
|||||||
Reference in New Issue
Block a user