fix: table list action
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
import { atomWithStorage } from 'jotai/utils';
|
||||
|
||||
export const userAtom = atomWithStorage<any>('userInfo', null);
|
||||
|
||||
export const initialPasswordAtom = atomWithStorage<string>(
|
||||
'initialPassword',
|
||||
''
|
||||
);
|
||||
|
||||
@@ -25,7 +25,6 @@ const LineChart: React.FC<LineChartProps> = (props) => {
|
||||
labelFormatter
|
||||
} = props;
|
||||
const config = {
|
||||
title,
|
||||
height,
|
||||
xField: xField || 'time',
|
||||
yField: yField || 'value',
|
||||
@@ -50,6 +49,15 @@ const LineChart: React.FC<LineChartProps> = (props) => {
|
||||
style: {
|
||||
fill: 'rgba(84, 204, 152,0.8)'
|
||||
},
|
||||
title: {
|
||||
title,
|
||||
style: {
|
||||
align: 'center',
|
||||
titleFontSize: 14,
|
||||
titleFill: 'rgba(0,0,0,0.88)',
|
||||
titleFontWeight: 500
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
color: {
|
||||
layout: { justifyContent: 'center' }
|
||||
|
||||
@@ -85,15 +85,14 @@ const BarChart: React.FC<BarChartProps> = (props) => {
|
||||
},
|
||||
|
||||
style: {
|
||||
// fill: (params: any) => {
|
||||
// return (
|
||||
// params.color ||
|
||||
// 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)'
|
||||
// );
|
||||
// },
|
||||
fill: (params: any) => {
|
||||
return (
|
||||
params.color ||
|
||||
'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)'
|
||||
);
|
||||
},
|
||||
// radiusTopLeft: 12,
|
||||
// radiusTopRight: 12,
|
||||
fill: 'rgba(84, 204, 152,0.8)',
|
||||
align: 'center',
|
||||
width: 20
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
export const titleStyle = {
|
||||
style: {
|
||||
align: 'center',
|
||||
titleFontSize: 14,
|
||||
titleFill: 'rgba(0,0,0,0.88)',
|
||||
titleFontWeight: 500
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
import { MoreOutlined } from '@ant-design/icons';
|
||||
import { Button, Dropdown, Tooltip, type MenuProps } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
||||
interface DropdownButtonsProps {
|
||||
items: MenuProps['items'];
|
||||
size?: 'small' | 'middle' | 'large';
|
||||
onSelect: (val: any, item?: any) => void;
|
||||
}
|
||||
|
||||
const DropdownButtons: React.FC<DropdownButtonsProps> = ({
|
||||
items,
|
||||
size = 'small',
|
||||
onSelect
|
||||
}) => {
|
||||
const handleMenuClick = (item: any) => {
|
||||
console.log('menu click', item.key);
|
||||
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 null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{items?.length === 1 ? (
|
||||
<Button
|
||||
icon={_.get(items, '0.icon')}
|
||||
size={size}
|
||||
onClick={handleButtonClick}
|
||||
></Button>
|
||||
) : (
|
||||
<Dropdown.Button
|
||||
menu={{
|
||||
items: _.tail(items),
|
||||
onClick: handleMenuClick
|
||||
}}
|
||||
buttonsRender={([leftButton, rightButton]) => [
|
||||
<Tooltip title={_.head(items)?.label} key="leftButton">
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
size={size}
|
||||
icon={_.head(items)?.icon}
|
||||
></Button>
|
||||
</Tooltip>,
|
||||
<Button icon={<MoreOutlined />} size={size} key="menu"></Button>
|
||||
]}
|
||||
></Dropdown.Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownButtons;
|
||||
@@ -39,7 +39,6 @@ const SealInputNumber: React.FC<InputNumberProps & SealFormItemProps> = (
|
||||
};
|
||||
|
||||
const handleChange = (e: any) => {
|
||||
e.target.value = e.target.value?.trim?.();
|
||||
props.onChange?.(e);
|
||||
};
|
||||
|
||||
@@ -49,7 +48,6 @@ const SealInputNumber: React.FC<InputNumberProps & SealFormItemProps> = (
|
||||
};
|
||||
|
||||
const handleOnBlur = (e: any) => {
|
||||
e.target.value = e.target.value?.trim?.();
|
||||
if (!inputRef.current?.value) {
|
||||
setIsFocus(false);
|
||||
props.onBlur?.(e);
|
||||
|
||||
@@ -6,19 +6,20 @@ export default {
|
||||
'dashboard.allocategpus': 'Allocated GPUs',
|
||||
'dashboard.instances': 'Instances',
|
||||
'dashboard.systemload': 'System Load',
|
||||
'dashboard.memory': 'Memory',
|
||||
'dashboard.memory': 'RAM',
|
||||
'dashboard.disk': 'Storage',
|
||||
'dashboard.vram': 'VRAM',
|
||||
'dashboard.cpuutilization': 'CPU Utilization',
|
||||
'dashboard.memoryutilization': 'Memory Utilization',
|
||||
'dashboard.memoryutilization': 'RAM Utilization',
|
||||
'dashboard.diskutilization': 'Storage Utilization',
|
||||
'dashboard.vramutilization': 'VRAM Utilization',
|
||||
'dashboard.gpuutilization': 'GPU Utilization',
|
||||
'dashboard.usage': 'Usage',
|
||||
'dashboard.apirequest': 'API Request',
|
||||
'dashboard.tokens': 'Tokens',
|
||||
'dashboard.tokens': 'Token Usage',
|
||||
'dashboard.topusers': 'Top Users',
|
||||
'dashboard.activeModels': 'Active Models',
|
||||
'dashboard.runninginstances': 'Running Instances',
|
||||
'dashboard.activeModels.name': 'Model Name'
|
||||
'dashboard.activeModels.name': 'Model Name',
|
||||
'dashboard.allocatevram': 'Allocated VRAM'
|
||||
};
|
||||
|
||||
@@ -4,12 +4,12 @@ export default {
|
||||
'resources.table.hostname': 'Hostname',
|
||||
'resources.table.ip': 'IP',
|
||||
'resources.table.cpu': 'CPU',
|
||||
'resources.table.memory': 'Memory',
|
||||
'resources.table.memory': 'RAM',
|
||||
'resources.table.gpu': 'GPU',
|
||||
'resources.table.disk': 'Storage',
|
||||
'resources.table.vram': 'VRAM',
|
||||
'resources.table.index': 'Index',
|
||||
'resources.table.workername': 'Wroker Name',
|
||||
'resources.table.workername': 'Worker Name',
|
||||
'resources.table.vender': 'Vender',
|
||||
'resources.table.temperature': 'Temperature',
|
||||
'resources.table.core': 'Core',
|
||||
|
||||
@@ -16,9 +16,10 @@ export default {
|
||||
'dashboard.gpuutilization': 'GPU 利用率',
|
||||
'dashboard.usage': '使用量',
|
||||
'dashboard.apirequest': 'API 请求',
|
||||
'dashboard.tokens': 'Tokens',
|
||||
'dashboard.tokens': 'Token 使用量',
|
||||
'dashboard.topusers': '用户排行',
|
||||
'dashboard.activeModels': '活跃模型',
|
||||
'dashboard.activeModels.name': '模型名称',
|
||||
'dashboard.runninginstances': '运行实例'
|
||||
'dashboard.runninginstances': '运行实例',
|
||||
'dashboard.allocatevram': '已分配显存'
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import PageTools from '@/components/page-tools';
|
||||
import ProgressBar from '@/components/progress-bar';
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Col, Row, Table } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useContext } from 'react';
|
||||
import { DashboardContext } from '../config/dashboard-context';
|
||||
|
||||
@@ -77,21 +76,19 @@ const ActiveTable = () => {
|
||||
dataIndex: 'name',
|
||||
key: 'name'
|
||||
},
|
||||
// {
|
||||
// title: intl.formatMessage({ id: 'dashboard.gpuutilization' }),
|
||||
// dataIndex: 'gpu_utilization',
|
||||
// key: 'gpu_utilization',
|
||||
// render: (text: any, record: any) => (
|
||||
// <ProgressBar percent={_.round(text, 0)}></ProgressBar>
|
||||
// )
|
||||
// },
|
||||
{
|
||||
title: intl.formatMessage({ id: 'dashboard.gpuutilization' }),
|
||||
dataIndex: 'gpu_utilization',
|
||||
key: 'gpu_utilization',
|
||||
render: (text: any, record: any) => (
|
||||
<ProgressBar percent={_.round(text, 0)}></ProgressBar>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'dashboard.vramutilization' }),
|
||||
dataIndex: 'gpu_memory_utilization',
|
||||
title: intl.formatMessage({ id: 'dashboard.allocatevram' }),
|
||||
dataIndex: 'allocate_gpu_memory_utilization',
|
||||
key: 'gpu_memory_utilization',
|
||||
render: (text: any, record: any) => (
|
||||
<ProgressBar percent={_.round(text, 0)}></ProgressBar>
|
||||
)
|
||||
render: (text: any, record: any) => <span>{convertFileSize(text)}</span>
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'dashboard.runninginstances' }),
|
||||
@@ -99,7 +96,7 @@ const ActiveTable = () => {
|
||||
key: 'instance_count'
|
||||
},
|
||||
{
|
||||
title: 'Tokens',
|
||||
title: intl.formatMessage({ id: 'dashboard.tokens' }),
|
||||
dataIndex: 'token_count',
|
||||
key: 'token_count'
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ const Overview: React.FC = () => {
|
||||
<Col
|
||||
xs={{ flex: '100%' }}
|
||||
sm={{ flex: '50%' }}
|
||||
md={{ flex: '30%' }}
|
||||
lg={{ flex: '20%' }}
|
||||
xl={{ flex: '20%' }}
|
||||
md={{ flex: '50%' }}
|
||||
lg={{ flex: '25%' }}
|
||||
xl={{ flex: '25%' }}
|
||||
key={config.key}
|
||||
>
|
||||
{renderCardItem({
|
||||
|
||||
@@ -67,7 +67,7 @@ const UtilizationOvertime: React.FC = () => {
|
||||
const list: { value: number; time: string; type: string }[] = [];
|
||||
_.each(typeList, (type: any) => {
|
||||
const dataList = _.map(_.get(data, type, []), (item: any) => {
|
||||
const value = _.get(item, 'value', 0);
|
||||
const value = _.round(_.get(item, 'value', 0), 1);
|
||||
const time = dayjs(item.timestamp * 1000).format('HH:mm:ss');
|
||||
const itemtype = _.get(TypeKeyMap, [type, 'intl'], false)
|
||||
? intl.formatMessage({
|
||||
|
||||
@@ -92,6 +92,19 @@ const tokenUsage = TokensData.map((val, i) => {
|
||||
};
|
||||
});
|
||||
|
||||
const getCurrentMonthDays = () => {
|
||||
const now = dayjs();
|
||||
const firstDayOfMonth = now.startOf('month');
|
||||
const dateRange = [];
|
||||
let currentDate = firstDayOfMonth;
|
||||
|
||||
while (currentDate.isBefore(now) || currentDate.isSame(now, 'day')) {
|
||||
dateRange.push(currentDate.format('YYYY-MM-DD'));
|
||||
currentDate = currentDate.add(1, 'day');
|
||||
}
|
||||
return dateRange;
|
||||
};
|
||||
|
||||
const Usage = () => {
|
||||
const intl = useIntl();
|
||||
const { size } = useWindowResize();
|
||||
@@ -105,8 +118,11 @@ const Usage = () => {
|
||||
const [userData, setUserData] = useState<{ name: string; value: number }[]>(
|
||||
[]
|
||||
);
|
||||
const [dateRange, setDateRange] = useState<string[]>(getCurrentMonthDays());
|
||||
|
||||
const data = useContext(DashboardContext)?.model_usage || {};
|
||||
|
||||
console.log('dateRange', dateRange);
|
||||
const handleSelectDate = (dateString: string) => {};
|
||||
|
||||
const generateData = () => {
|
||||
@@ -126,26 +142,67 @@ const Usage = () => {
|
||||
|
||||
_.each(data.api_request_history, (item: any) => {
|
||||
requestList.push({
|
||||
time: dayjs(item.timestamp * 1000).format('YYYY-MM'),
|
||||
time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'),
|
||||
value: item.value
|
||||
});
|
||||
});
|
||||
|
||||
_.each(data.completion_token_history, (item: any) => {
|
||||
tokenList.push({
|
||||
time: dayjs(item.timestamp * 1000).format('YYYY-MM'),
|
||||
name: 'completion_token',
|
||||
color: 'rgba(84, 204, 152,0.8)',
|
||||
value: item.value
|
||||
_.each(dateRange, (date: string) => {
|
||||
// tokens data
|
||||
const item = _.find(data.completion_token_history, (item: any) => {
|
||||
return dayjs(item.timestamp * 1000).format('YYYY-MM-DD') === date;
|
||||
});
|
||||
});
|
||||
_.each(data.prompt_token_history, (item: any) => {
|
||||
tokenList.push({
|
||||
time: dayjs(item.timestamp * 1000).format('YYYY-MM'),
|
||||
name: 'prompt_token',
|
||||
color: 'rgba(0, 170, 173, 0.8)',
|
||||
value: item.value
|
||||
if (!item) {
|
||||
tokenList.push({
|
||||
time: date,
|
||||
name: 'completion_token',
|
||||
color: 'rgba(84, 204, 152,0.8)',
|
||||
value: 0
|
||||
});
|
||||
} else {
|
||||
tokenList.push({
|
||||
time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'),
|
||||
name: 'completion_token',
|
||||
color: 'rgba(84, 204, 152,0.8)',
|
||||
value: item.value
|
||||
});
|
||||
}
|
||||
|
||||
const promptItem = _.find(data.prompt_token_history, (item: any) => {
|
||||
return dayjs(item.timestamp * 1000).format('YYYY-MM-DD') === date;
|
||||
});
|
||||
if (!promptItem) {
|
||||
tokenList.push({
|
||||
time: date,
|
||||
name: 'prompt_token',
|
||||
color: 'rgba(0, 170, 173, 0.8)',
|
||||
value: 0
|
||||
});
|
||||
} else {
|
||||
tokenList.push({
|
||||
time: dayjs(promptItem.timestamp * 1000).format('YYYY-MM-DD'),
|
||||
name: 'prompt_token',
|
||||
color: 'rgba(0, 170, 173, 0.8)',
|
||||
value: promptItem.value
|
||||
});
|
||||
}
|
||||
|
||||
// api request data
|
||||
const requestItem = _.find(data.api_request_history, (item: any) => {
|
||||
return dayjs(item.timestamp * 1000).format('YYYY-MM-DD') === date;
|
||||
});
|
||||
|
||||
if (!requestItem) {
|
||||
requestList.push({
|
||||
time: date,
|
||||
value: 0
|
||||
});
|
||||
} else {
|
||||
requestList.push({
|
||||
time: dayjs(requestItem.timestamp * 1000).format('YYYY-MM-DD'),
|
||||
value: requestItem.value
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_.each(data.top_users, (item: any) => {
|
||||
@@ -190,7 +247,7 @@ const Usage = () => {
|
||||
</span>
|
||||
}
|
||||
right={
|
||||
<RangePicker
|
||||
<DatePicker
|
||||
onChange={handleSelectDate}
|
||||
style={{ width: 300 }}
|
||||
picker="month"
|
||||
|
||||
@@ -11,12 +11,12 @@ export const overviewConfigs = [
|
||||
backgroundColor: 'var(--color-white-1)'
|
||||
// backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))'
|
||||
},
|
||||
{
|
||||
key: 'allocatedGpus',
|
||||
label: 'dashboard.allocategpus',
|
||||
backgroundColor: 'var(--color-white-1)'
|
||||
// backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))'
|
||||
},
|
||||
// {
|
||||
// key: 'allocatedGpus',
|
||||
// label: 'dashboard.allocategpus',
|
||||
// backgroundColor: 'var(--color-white-1)'
|
||||
// // backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))'
|
||||
// },
|
||||
{
|
||||
key: 'model_count',
|
||||
label: 'dashboard.models',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { StatusMaps } from '@/config';
|
||||
import { EditOutlined } from '@ant-design/icons';
|
||||
|
||||
export const ollamaModelOptions = [
|
||||
{ label: 'llama3', value: 'llama3' },
|
||||
@@ -20,3 +21,21 @@ export const modelSourceMap = {
|
||||
export const status: any = {
|
||||
Running: StatusMaps.success
|
||||
};
|
||||
|
||||
export const ActionList = [
|
||||
{
|
||||
label: 'common.button.edit',
|
||||
key: 'edit',
|
||||
icon: EditOutlined
|
||||
},
|
||||
{
|
||||
label: 'models.openinplayground',
|
||||
key: 'chat',
|
||||
icon: EditOutlined
|
||||
},
|
||||
{
|
||||
label: 'common.button.delete',
|
||||
key: 'delete',
|
||||
icon: EditOutlined
|
||||
}
|
||||
];
|
||||
|
||||
@@ -31,6 +31,7 @@ export interface ModelInstanceListItem {
|
||||
gpu_index: number;
|
||||
pid: number;
|
||||
port: number;
|
||||
name: string;
|
||||
state: string;
|
||||
download_progress: number;
|
||||
model_id: number;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import DropdownButtons from '@/components/drop-down-buttons';
|
||||
import PageTools from '@/components/page-tools';
|
||||
import SealTable from '@/components/seal-table';
|
||||
import RowChildren from '@/components/seal-table/components/row-children';
|
||||
@@ -24,17 +25,7 @@ import {
|
||||
} from '@ant-design/icons';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { Access, useAccess, useIntl, useNavigate } from '@umijs/max';
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Input,
|
||||
Modal,
|
||||
Row,
|
||||
Space,
|
||||
Tag,
|
||||
Tooltip,
|
||||
message
|
||||
} from 'antd';
|
||||
import { Button, Col, Input, Modal, Row, Space, message } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import _ from 'lodash';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
@@ -79,6 +70,38 @@ const Models: React.FC = () => {
|
||||
);
|
||||
const [currentInstanceUrl, setCurrentInstanceUrl] = useState<string>('');
|
||||
|
||||
const ActionList = [
|
||||
{
|
||||
label: intl.formatMessage({ id: 'common.button.edit' }),
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'models.openinplayground' }),
|
||||
key: 'chat',
|
||||
icon: <WechatWorkOutlined />
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'common.button.delete' }),
|
||||
key: 'delete',
|
||||
danger: true,
|
||||
icon: <DeleteOutlined />
|
||||
}
|
||||
];
|
||||
|
||||
const childActionList = [
|
||||
{
|
||||
label: intl.formatMessage({ id: 'common.button.viewlog' }),
|
||||
key: 'viewlog',
|
||||
icon: <FieldTimeOutlined />
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'common.button.delete' }),
|
||||
key: 'delete',
|
||||
danger: true,
|
||||
icon: <DeleteOutlined />
|
||||
}
|
||||
];
|
||||
const chunkRequedtRef = useRef<any>();
|
||||
const timer = useRef<any>();
|
||||
let axiosToken = createAxiosToken();
|
||||
@@ -370,6 +393,27 @@ const Models: React.FC = () => {
|
||||
setTitle(intl.formatMessage({ id: 'models.title.edit' }));
|
||||
};
|
||||
|
||||
const handleSelect = (val: any, row: ListItem) => {
|
||||
if (val === 'edit') {
|
||||
handleEdit(row);
|
||||
}
|
||||
if (val === 'chat') {
|
||||
handleOpenPlayGround(row);
|
||||
}
|
||||
if (val === 'delete') {
|
||||
handleDelete(row);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChildSelect = (val: any, row: ModelInstanceListItem) => {
|
||||
if (val === 'delete') {
|
||||
handleDeleteInstace(row);
|
||||
}
|
||||
if (val === 'viewlog') {
|
||||
handleViewLogs(row);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// fetchData();
|
||||
createModelsChunkRequest();
|
||||
@@ -394,10 +438,7 @@ const Models: React.FC = () => {
|
||||
>
|
||||
<RowChildren key={`${item.id}_row`}>
|
||||
<Row style={{ width: '100%' }} align="middle">
|
||||
<Col span={6}>
|
||||
<Tag>{item.gpu_index}</Tag>
|
||||
{item.worker_ip}:{item.port}
|
||||
</Col>
|
||||
<Col span={6}>{item.name}</Col>
|
||||
<Col span={4}>
|
||||
<span>{item.huggingface_filename}</span>
|
||||
</Col>
|
||||
@@ -423,33 +464,10 @@ const Models: React.FC = () => {
|
||||
</span>
|
||||
</Col>
|
||||
<Col span={5}>
|
||||
{hoverChildIndex === `${item.id}-${index}` && (
|
||||
<Space size={20}>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'common.button.delete'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
danger
|
||||
onClick={() => handleDeleteInstace(item)}
|
||||
icon={<DeleteOutlined></DeleteOutlined>}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'common.button.viewlog'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => handleViewLogs(item)}
|
||||
icon={<FieldTimeOutlined />}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
)}
|
||||
<DropdownButtons
|
||||
items={childActionList}
|
||||
onSelect={(val) => handleChildSelect(val, item)}
|
||||
></DropdownButtons>
|
||||
</Col>
|
||||
</Row>
|
||||
</RowChildren>
|
||||
@@ -570,43 +588,10 @@ const Models: React.FC = () => {
|
||||
key="operation"
|
||||
render={(text, record) => {
|
||||
return !record.transition ? (
|
||||
<Space size={20}>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'common.button.edit'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
onClick={() => handleEdit(record)}
|
||||
icon={<EditOutlined></EditOutlined>}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'models.openinplayground'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
onClick={() => handleOpenPlayGround(record)}
|
||||
icon={<WechatWorkOutlined />}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({ id: 'common.button.delete' })}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
danger
|
||||
onClick={() => handleDelete(record)}
|
||||
icon={<DeleteOutlined></DeleteOutlined>}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
<DropdownButtons
|
||||
items={ActionList}
|
||||
onSelect={(val) => handleSelect(val, record)}
|
||||
></DropdownButtons>
|
||||
) : null;
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import LogoIcon from '@/assets/images/logo.png';
|
||||
import { userAtom } from '@/atoms/user';
|
||||
import { initialPasswordAtom, userAtom } from '@/atoms/user';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import { GlobalOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import { SelectLang, history, useIntl, useModel } from '@umijs/max';
|
||||
@@ -26,6 +26,7 @@ const renderLogo = () => {
|
||||
};
|
||||
const LoginForm = () => {
|
||||
const [userInfo, setUserInfo] = useAtom(userAtom);
|
||||
const [initialPassword, setInitialPassword] = useAtom(initialPasswordAtom);
|
||||
const { initialState, setInitialState } = useModel('@@initialState');
|
||||
const { globalState, setGlobalState } = useModel('global');
|
||||
const intl = useIntl();
|
||||
@@ -62,6 +63,7 @@ const LoginForm = () => {
|
||||
userInfo
|
||||
});
|
||||
setUserInfo(userInfo);
|
||||
setInitialPassword(values.password);
|
||||
if (!userInfo?.require_password_change) {
|
||||
gotoDefaultPage(userInfo);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { userAtom } from '@/atoms/user';
|
||||
import { initialPasswordAtom, userAtom } from '@/atoms/user';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import { PasswordReg } from '@/config';
|
||||
import { GlobalOutlined, LockOutlined } from '@ant-design/icons';
|
||||
@@ -12,6 +12,7 @@ const PasswordForm: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const [userInfo, setUserInfo] = useAtom(userAtom);
|
||||
const [initialPassword, setInitialPassword] = useAtom(initialPasswordAtom);
|
||||
const gotoDefaultPage = (userInfo: any) => {
|
||||
const pathname =
|
||||
userInfo && userInfo?.is_admin ? '/dashboard' : '/playground';
|
||||
@@ -23,13 +24,14 @@ const PasswordForm: React.FC = () => {
|
||||
try {
|
||||
await updatePassword({
|
||||
new_password: values.new_password,
|
||||
current_password: values.current_password
|
||||
current_password: initialPassword
|
||||
});
|
||||
|
||||
await setUserInfo({
|
||||
...userInfo,
|
||||
require_password_change: false
|
||||
});
|
||||
setInitialPassword('');
|
||||
gotoDefaultPage(userInfo);
|
||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||
} catch (error) {
|
||||
@@ -63,7 +65,7 @@ const PasswordForm: React.FC = () => {
|
||||
{intl.formatMessage({ id: 'users.password.modify.description' })}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
{/*
|
||||
<Form.Item
|
||||
name="current_password"
|
||||
rules={[
|
||||
@@ -82,7 +84,7 @@ const PasswordForm: React.FC = () => {
|
||||
prefix={<LockOutlined />}
|
||||
label={intl.formatMessage({ id: 'users.form.currentpassword' })}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form.Item> */}
|
||||
<Form.Item
|
||||
name="new_password"
|
||||
rules={[
|
||||
|
||||
+27
-24
@@ -1,3 +1,4 @@
|
||||
import DropdownButtons from '@/components/drop-down-buttons';
|
||||
import PageTools from '@/components/page-tools';
|
||||
import { PageAction } from '@/config';
|
||||
import type { PageActionType } from '@/config/types';
|
||||
@@ -14,7 +15,7 @@ import {
|
||||
} from '@ant-design/icons';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Input, Modal, Space, Table, Tooltip, message } from 'antd';
|
||||
import { Button, Input, Modal, Space, Table, message } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -44,6 +45,19 @@ const Models: React.FC = () => {
|
||||
query: ''
|
||||
});
|
||||
|
||||
const ActionList = [
|
||||
{
|
||||
key: 'edit',
|
||||
label: intl.formatMessage({ id: 'common.button.edit' }),
|
||||
icon: <EditOutlined></EditOutlined>
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
danger: true,
|
||||
label: intl.formatMessage({ id: 'common.button.delete' }),
|
||||
icon: <DeleteOutlined></DeleteOutlined>
|
||||
}
|
||||
];
|
||||
const fetchData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
@@ -172,6 +186,14 @@ const Models: React.FC = () => {
|
||||
setTitle(intl.formatMessage({ id: 'users.form.edit' }));
|
||||
};
|
||||
|
||||
const handleSelect = (val: any, row: ListItem) => {
|
||||
if (val === 'edit') {
|
||||
handleEditUser(row);
|
||||
} else if (val === 'delete') {
|
||||
handleDelete(row);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [queryParams]);
|
||||
@@ -296,29 +318,10 @@ const Models: React.FC = () => {
|
||||
width={200}
|
||||
render={(text, record: ListItem) => {
|
||||
return (
|
||||
<Space size={20}>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({ id: 'common.button.edit' })}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
onClick={() => handleEditUser(record)}
|
||||
icon={<EditOutlined></EditOutlined>}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({ id: 'common.button.delete' })}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
danger
|
||||
onClick={() => handleDelete(record)}
|
||||
icon={<DeleteOutlined></DeleteOutlined>}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
<DropdownButtons
|
||||
items={ActionList}
|
||||
onSelect={(val) => handleSelect(val, record)}
|
||||
></DropdownButtons>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
+2
-2
@@ -20,9 +20,9 @@ export const handleBatchRequest = async (
|
||||
};
|
||||
|
||||
export const convertFileSize = (sizeInBytes: number, prec?: number) => {
|
||||
const precision = prec ?? 2;
|
||||
const precision = prec ?? 1;
|
||||
if (!sizeInBytes) {
|
||||
return '0 B';
|
||||
return '0';
|
||||
}
|
||||
if (sizeInBytes < 1024) {
|
||||
return `${sizeInBytes.toFixed(precision)} B`;
|
||||
|
||||
Reference in New Issue
Block a user