refactor: credential table columns
This commit is contained in:
+2
-1
@@ -31,7 +31,7 @@
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"ahooks": "^3.8.5",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"antd": "^5.21.6",
|
||||
"antd": "^5.25.4",
|
||||
"antd-style": "^3.6.2",
|
||||
"axios": "^1.8.2",
|
||||
"classnames": "^2.5.1",
|
||||
@@ -73,6 +73,7 @@
|
||||
"remark-math": "^6.0.0",
|
||||
"simplebar-react": "^3.2.6",
|
||||
"styled-components": "^6.1.15",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"umi-presets-pro": "^2.0.3",
|
||||
"wavesurfer.js": "^7.8.8",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
||||
|
||||
Generated
+344
-304
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ import { Button, Dropdown, 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';
|
||||
@@ -19,6 +20,17 @@ interface DropdownButtonsProps {
|
||||
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,
|
||||
size = 'middle',
|
||||
@@ -66,16 +78,7 @@ const DropdownButtons: React.FC<DropdownButtonsProps> = ({
|
||||
type="primary"
|
||||
dropdownRender={(menus: any) => {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-column "
|
||||
style={{
|
||||
backgroundColor: 'var(--ant-color-bg-elevated)',
|
||||
padding: 5,
|
||||
alignItems: 'flex-start',
|
||||
borderRadius: 'var(--border-radius-base)',
|
||||
boxShadow: 'var(--ant-box-shadow-secondary)'
|
||||
}}
|
||||
>
|
||||
<DropdownWrapper>
|
||||
{_.map(_.tail(items), (item: any) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -86,13 +89,17 @@ const DropdownButtons: React.FC<DropdownButtonsProps> = ({
|
||||
key={item.key}
|
||||
disabled={item.disabled}
|
||||
onClick={() => handleMenuClick(item)}
|
||||
style={{ width: '100%', justifyContent: 'flex-start' }}
|
||||
style={{
|
||||
width: '100%',
|
||||
justifyContent: 'flex-start',
|
||||
paddingInline: 10
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({ id: item.label })}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</DropdownWrapper>
|
||||
);
|
||||
}}
|
||||
buttonsRender={([leftButton, rightButton]) => [
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import Chart from '@/components/echarts/chart';
|
||||
import useChartConfig from '@/components/echarts/config';
|
||||
import EmptyData from '@/components/empty-data';
|
||||
import { genColors } from '@/utils';
|
||||
import _ from 'lodash';
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import echarts from '.';
|
||||
import { ChartProps } from './types';
|
||||
|
||||
const LinearGradient = echarts.graphic.LinearGradient;
|
||||
const LineChart: React.FC<ChartProps> = (props) => {
|
||||
const {
|
||||
seriesData,
|
||||
@@ -81,6 +84,11 @@ const LineChart: React.FC<ChartProps> = (props) => {
|
||||
|
||||
const dataOptions = useMemo((): any => {
|
||||
const data = _.map(seriesData, (item: any) => {
|
||||
const colors = genColors({
|
||||
color: item.color,
|
||||
alpha1: 0.5,
|
||||
alpha2: 0.1
|
||||
});
|
||||
return {
|
||||
...item,
|
||||
...lineItemConfig,
|
||||
@@ -93,6 +101,18 @@ const LineChart: React.FC<ChartProps> = (props) => {
|
||||
...lineItemConfig.lineStyle,
|
||||
color: item.color
|
||||
}
|
||||
// areaStyle: {
|
||||
// color: new LinearGradient(0, 0, 0, 1, [
|
||||
// {
|
||||
// offset: 0,
|
||||
// color: colors[0]
|
||||
// },
|
||||
// {
|
||||
// offset: 1,
|
||||
// color: colors[1]
|
||||
// }
|
||||
// ])
|
||||
// }
|
||||
};
|
||||
});
|
||||
return {
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import Chart from '@/components/echarts/chart';
|
||||
import useChartConfig from '@/components/echarts/config';
|
||||
import EmptyData from '@/components/empty-data';
|
||||
import { genColors } from '@/utils';
|
||||
import _ from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import echarts from '.';
|
||||
import { ChartProps } from './types';
|
||||
|
||||
const LinearGradient = echarts.graphic.LinearGradient;
|
||||
|
||||
const MixLineBarChart: React.FC<
|
||||
ChartProps & {
|
||||
chartData: {
|
||||
@@ -78,6 +82,11 @@ const MixLineBarChart: React.FC<
|
||||
|
||||
const dataOptions = useMemo((): any => {
|
||||
const linedata = _.map(lineSeriesData, (item: any) => {
|
||||
const colors = genColors({
|
||||
color: item.color,
|
||||
alpha1: 0.5,
|
||||
alpha2: 0.1
|
||||
});
|
||||
return {
|
||||
...item,
|
||||
...lineItemConfig,
|
||||
@@ -91,6 +100,18 @@ const MixLineBarChart: React.FC<
|
||||
...lineItemConfig.lineStyle,
|
||||
color: item.color
|
||||
}
|
||||
// areaStyle: {
|
||||
// color: new LinearGradient(0, 0, 0, 1, [
|
||||
// {
|
||||
// offset: 0,
|
||||
// color: colors[0]
|
||||
// },
|
||||
// {
|
||||
// offset: 1,
|
||||
// color: colors[1]
|
||||
// }
|
||||
// ])
|
||||
// }
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ const ScrollerModal = (props: ModalProps & { maxContentHeight?: number }) => {
|
||||
return (
|
||||
<Modal
|
||||
{...props}
|
||||
destroyOnClose={true}
|
||||
styles={{
|
||||
content: {
|
||||
padding: 0
|
||||
|
||||
@@ -14,9 +14,9 @@ type WatchConfig =
|
||||
| { watch: true; API: string; polling?: false | undefined }
|
||||
| { polling: true; watch: false | undefined; API?: string };
|
||||
|
||||
export default function useTableFetch<ListItem>(
|
||||
export default function useTableFetch<T>(
|
||||
options: {
|
||||
fetchAPI: (params: any) => Promise<Global.PageResponse<ListItem>>;
|
||||
fetchAPI: (params: any) => Promise<Global.PageResponse<T>>;
|
||||
deleteAPI?: (id: number, params?: any) => Promise<any>;
|
||||
contentForDelete?: string;
|
||||
defaultData?: any[];
|
||||
@@ -47,7 +47,7 @@ export default function useTableFetch<ListItem>(
|
||||
});
|
||||
|
||||
const [dataSource, setDataSource] = useState<{
|
||||
dataList: ListItem[];
|
||||
dataList: T[];
|
||||
loading: boolean;
|
||||
loadend: boolean;
|
||||
total: number;
|
||||
@@ -217,7 +217,7 @@ export default function useTableFetch<ListItem>(
|
||||
const handleNameChange = debounceUpdateFilter;
|
||||
|
||||
const handleDelete = (
|
||||
row: ListItem & { name: string; id: number },
|
||||
row: T & { name: string; id: number },
|
||||
options?: any
|
||||
) => {
|
||||
modalRef.current?.show({
|
||||
|
||||
@@ -10,5 +10,6 @@ export default {
|
||||
'clusters.edit.cluster': 'Edit {cluster}',
|
||||
'clusters.provider.custom': 'Custom',
|
||||
'clusters.button.register': 'Register Cluster',
|
||||
'clusters.button.addNodePool': 'Add Node Pool'
|
||||
'clusters.button.addNodePool': 'Add Node Pool',
|
||||
'clusters.button.add.credential': 'Add {provider} Credential'
|
||||
};
|
||||
|
||||
@@ -91,5 +91,6 @@ export default {
|
||||
'resources.register.download':
|
||||
'Download and install the <a href={url} target="_blank">installer</a>. Only supported: {versions}.',
|
||||
'resource.register.maos.support': 'Apple Silicon (M series), macOS 14+',
|
||||
'resource.register.windows.support': 'win 10, win 11'
|
||||
'resource.register.windows.support': 'win 10, win 11',
|
||||
'resources.model.instance': 'Model Instance'
|
||||
};
|
||||
|
||||
@@ -10,7 +10,8 @@ export default {
|
||||
'clusters.edit.cluster': 'Edit {cluster}',
|
||||
'clusters.provider.custom': 'Custom',
|
||||
'clusters.button.register': 'Register Cluster',
|
||||
'clusters.button.addNodePool': 'Add Node Pool'
|
||||
'clusters.button.addNodePool': 'Add Node Pool',
|
||||
'clusters.button.add.credential': 'Add {provider} Credential'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
@@ -25,5 +26,6 @@ export default {
|
||||
// 9. 'clusters.edit.cluster': 'Edit {cluster}',
|
||||
// 10. 'clusters.provider.custom': 'Custom',
|
||||
// 11. 'clusters.button.register': 'Register Cluster',
|
||||
// 12. 'clusters.button.addNodePool': 'Add Node Pool'
|
||||
// 12. 'clusters.button.addNodePool': 'Add Node Pool',
|
||||
// 13. 'clusters.button.add.credential': 'Add {provider} Credential'
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -92,7 +92,8 @@ export default {
|
||||
'resources.register.download':
|
||||
'Download and install the <a href={url} target="_blank">installer</a>. Only supported: {versions}.',
|
||||
'resource.register.maos.support': 'Apple Silicon (M series), macOS 14+',
|
||||
'resource.register.windows.support': 'win 10, win 11'
|
||||
'resource.register.windows.support': 'win 10, win 11',
|
||||
'resources.model.instance': 'Model Instance'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
@@ -108,4 +109,5 @@ export default {
|
||||
// 10. 'resource.register.maos.support': 'Apple Silicon (M series), macOS 14+',
|
||||
// 11. 'resource.register.windows.support': 'win 10, win 11',
|
||||
// 12. 'resources.filter.status': 'Filter by Status',
|
||||
// 13. 'resources.model.instance': 'Model Instance'
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -10,7 +10,8 @@ export default {
|
||||
'clusters.edit.cluster': 'Edit {cluster}',
|
||||
'clusters.provider.custom': 'Custom',
|
||||
'clusters.button.register': 'Register Cluster',
|
||||
'clusters.button.addNodePool': 'Add Node Pool'
|
||||
'clusters.button.addNodePool': 'Add Node Pool',
|
||||
'clusters.button.add.credential': 'Add {provider} Credential'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
@@ -25,5 +26,6 @@ export default {
|
||||
// 9. 'clusters.edit.cluster': 'Edit {cluster}',
|
||||
// 10. 'clusters.provider.custom': 'Custom',
|
||||
// 11. 'clusters.button.register': 'Register Cluster',
|
||||
// 12. 'clusters.button.addNodePool': 'Add Node Pool'
|
||||
// 12. 'clusters.button.addNodePool': 'Add Node Pool',
|
||||
// 13. 'clusters.button.add.credential': 'Add {provider} Credential'
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -90,7 +90,8 @@ export default {
|
||||
'resources.register.download':
|
||||
'Скачайте и установите <a href={url} target="_blank">инсталлятор</a>. Поддерживаемые версии: {versions}.',
|
||||
'resource.register.maos.support': 'Apple Silicon (серия M), macOS 14+',
|
||||
'resource.register.windows.support': 'Windows 10, Windows 11'
|
||||
'resource.register.windows.support': 'Windows 10, Windows 11',
|
||||
'resources.model.instance': 'Модель экземпляра'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
|
||||
@@ -10,5 +10,6 @@ export default {
|
||||
'clusters.edit.cluster': '编辑 {cluster}',
|
||||
'clusters.provider.custom': '自定义',
|
||||
'clusters.button.register': '注册集群',
|
||||
'clusters.button.addNodePool': '添加节点池'
|
||||
'clusters.button.addNodePool': '添加节点池',
|
||||
'clusters.button.add.credential': '添加 {provider} 凭证'
|
||||
};
|
||||
|
||||
@@ -89,5 +89,6 @@ export default {
|
||||
'resources.register.download':
|
||||
'下载并安装<a href={url} target="_blank">安装包</a>,仅支持 {versions}。',
|
||||
'resource.register.maos.support': 'M 芯片,macOS 14+',
|
||||
'resource.register.windows.support': 'win 10, win 11'
|
||||
'resource.register.windows.support': 'win 10, win 11',
|
||||
'resources.model.instance': '模型实例'
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ const Credentials: React.FC = () => {
|
||||
} = useTableFetch<ListItem>({
|
||||
fetchAPI: queryClusterList,
|
||||
deleteAPI: deleteCluster,
|
||||
contentForDelete: 'users.table.user'
|
||||
contentForDelete: 'menu.clusterManagement.clusters'
|
||||
});
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
ClusterListItem as ListItem
|
||||
} from '../config/types';
|
||||
import CloudProvider from './cloud-provider-form';
|
||||
import RegisterClusterInner from './resiter-cluster-inner';
|
||||
import RegisterClusterInner from './register-cluster-inner';
|
||||
|
||||
type AddModalProps = {
|
||||
title: string;
|
||||
|
||||
@@ -4,8 +4,8 @@ import SealInput from '@/components/seal-form/seal-input';
|
||||
import { PageAction } from '@/config';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Form } from 'antd';
|
||||
import React from 'react';
|
||||
import { Form } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
import { ProviderValueMap } from '../config';
|
||||
import {
|
||||
CredentialFormData as FormData,
|
||||
@@ -41,32 +41,32 @@ const AddModal: React.FC<AddModalProps> = ({
|
||||
onOk(data);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
form.resetFields();
|
||||
onCancel();
|
||||
};
|
||||
useEffect(() => {
|
||||
if (currentData) {
|
||||
form.setFieldsValue(currentData);
|
||||
}
|
||||
}, [currentData]);
|
||||
|
||||
return (
|
||||
<ScrollerModal
|
||||
title={title}
|
||||
open={open}
|
||||
centered={true}
|
||||
onOk={handleSumit}
|
||||
onCancel={onCancel}
|
||||
destroyOnClose={true}
|
||||
closeIcon={false}
|
||||
maskClosable={false}
|
||||
keyboard={false}
|
||||
width={600}
|
||||
footer={
|
||||
<ModalFooter
|
||||
onOk={handleSumit}
|
||||
onCancel={onCancel}
|
||||
description={<Button>Validation Test</Button>}
|
||||
></ModalFooter>
|
||||
<ModalFooter onOk={handleSumit} onCancel={handleCancel}></ModalFooter>
|
||||
}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={handleOk}
|
||||
preserve={false}
|
||||
initialValues={currentData}
|
||||
>
|
||||
<Form form={form} onFinish={handleOk} preserve={false}>
|
||||
<Form.Item<FormData>
|
||||
name="name"
|
||||
rules={[
|
||||
@@ -88,7 +88,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
||||
</Form.Item>
|
||||
{provider === ProviderValueMap.DigitalOcean && (
|
||||
<>
|
||||
<Form.Item<FormData>
|
||||
{/* <Form.Item<FormData>
|
||||
name="key"
|
||||
rules={[
|
||||
{
|
||||
@@ -103,20 +103,18 @@ const AddModal: React.FC<AddModalProps> = ({
|
||||
label="Access Key"
|
||||
required={action === PageAction.CREATE}
|
||||
></SealInput.Password>
|
||||
</Form.Item>
|
||||
</Form.Item> */}
|
||||
<Form.Item<FormData>
|
||||
name="secret"
|
||||
rules={[
|
||||
{
|
||||
required: action === PageAction.CREATE,
|
||||
message: intl.formatMessage({
|
||||
id: 'users.form.rule.password'
|
||||
})
|
||||
message: 'Access Token is required'
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Password
|
||||
label="Access Secret"
|
||||
label="Access Token"
|
||||
required={action === PageAction.CREATE}
|
||||
></SealInput.Password>
|
||||
</Form.Item>
|
||||
|
||||
@@ -25,6 +25,12 @@ const metricsMap = {
|
||||
intl: false,
|
||||
color: 'rgba(114, 46, 209,.8)'
|
||||
},
|
||||
allocated: {
|
||||
label: 'Allocated',
|
||||
type: 'Allocated',
|
||||
intl: false,
|
||||
color: 'rgba(250, 173, 20,.8)'
|
||||
},
|
||||
gpu: {
|
||||
label: 'GPU',
|
||||
type: 'GPU',
|
||||
@@ -186,7 +192,7 @@ const ClusterDetail: React.FC<ClusterDetailProps> = ({ data }) => {
|
||||
</Row>
|
||||
</div>
|
||||
<SubTitle>System Load</SubTitle>
|
||||
<Row style={{ marginBottom: 20 }} gutter={20}>
|
||||
<Row style={{ marginBottom: 16 }} gutter={16}>
|
||||
<Col span={12}>
|
||||
<Card height={CardHeight} clickable={false} ghost>
|
||||
<TrendChart
|
||||
@@ -208,14 +214,28 @@ const ClusterDetail: React.FC<ClusterDetailProps> = ({ data }) => {
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Card height={CardHeight} clickable={false} ghost>
|
||||
<TrendChart
|
||||
data={detailContent?.history}
|
||||
metrics={['cpu', 'gpu']}
|
||||
metricsMap={metricsMap}
|
||||
title="CPU & GPU"
|
||||
></TrendChart>
|
||||
</Card>
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Card height={CardHeight} clickable={false} ghost>
|
||||
<TrendChart
|
||||
data={detailContent?.history}
|
||||
metrics={['cpu']}
|
||||
metricsMap={metricsMap}
|
||||
title="CPU"
|
||||
></TrendChart>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Card height={CardHeight} clickable={false} ghost>
|
||||
<TrendChart
|
||||
data={detailContent?.history}
|
||||
metrics={['gpu']}
|
||||
metricsMap={metricsMap}
|
||||
title="GPU"
|
||||
></TrendChart>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
{data?.provider === ProviderValueMap.DigitalOcean && (
|
||||
<>
|
||||
<SubTitle>Worker Pools</SubTitle>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import ScrollerModal from '@/components/scroller-modal/index';
|
||||
import React from 'react';
|
||||
import RegisterClusterInner from './resiter-cluster-inner';
|
||||
import RegisterClusterInner from './register-cluster-inner';
|
||||
|
||||
type AddModalProps = {
|
||||
title: string;
|
||||
|
||||
@@ -38,6 +38,7 @@ const TrendChart: React.FC<TrendChartProps> = ({
|
||||
: itemConfig.label;
|
||||
legendData.push(name);
|
||||
const itemDataList = _.get(data, item, []);
|
||||
console.log('itemConfig:', itemConfig.color);
|
||||
return {
|
||||
name: name,
|
||||
color: itemConfig.color,
|
||||
|
||||
@@ -65,6 +65,22 @@ export const addActions = [
|
||||
}
|
||||
];
|
||||
|
||||
export const credentialActionList = [
|
||||
{
|
||||
key: 'edit',
|
||||
label: 'common.button.edit',
|
||||
icon: icons.EditOutlined
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
props: {
|
||||
danger: true
|
||||
},
|
||||
label: 'common.button.delete',
|
||||
icon: icons.DeleteOutlined
|
||||
}
|
||||
];
|
||||
|
||||
export const clusterActionList = [
|
||||
{
|
||||
key: 'edit',
|
||||
@@ -74,7 +90,7 @@ export const clusterActionList = [
|
||||
{
|
||||
key: 'details',
|
||||
label: 'common.button.detail',
|
||||
icon: icons.DetailInfo
|
||||
icon: icons.FileTextOutlined
|
||||
},
|
||||
{
|
||||
key: 'add_worker',
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
import AutoTooltip from '@/components/auto-tooltip';
|
||||
import DeleteModal from '@/components/delete-modal';
|
||||
import DropdownButtons from '@/components/drop-down-buttons';
|
||||
import IconFont from '@/components/icon-font';
|
||||
import { FilterBar } from '@/components/page-tools';
|
||||
import { PageAction } from '@/config';
|
||||
import type { PageActionType } from '@/config/types';
|
||||
import useTableFetch from '@/hooks/use-table-fetch';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
KubernetesOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { ConfigProvider, Empty, Table, message } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
createCredential,
|
||||
@@ -23,43 +16,20 @@ import {
|
||||
updateCredential
|
||||
} from './apis';
|
||||
import AddModal from './components/add-credential';
|
||||
import { ProviderValueMap } from './config';
|
||||
import { ProviderLabelMap, ProviderValueMap } from './config';
|
||||
import {
|
||||
CredentialFormData as FormData,
|
||||
CredentialListItem as ListItem
|
||||
} from './config/types';
|
||||
const { Column } = Table;
|
||||
|
||||
const ActionList = [
|
||||
{
|
||||
key: 'edit',
|
||||
label: 'common.button.edit',
|
||||
icon: <EditOutlined></EditOutlined>
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
props: {
|
||||
danger: true
|
||||
},
|
||||
label: 'common.button.delete',
|
||||
icon: <DeleteOutlined></DeleteOutlined>
|
||||
}
|
||||
];
|
||||
import useCredentialColumns from './hooks/use-credential-columns';
|
||||
|
||||
const addActions = [
|
||||
{
|
||||
label: 'Digital Ocean',
|
||||
locale: false,
|
||||
value: 'digital_ocean',
|
||||
key: 'digital_ocean',
|
||||
key: ProviderValueMap.DigitalOcean,
|
||||
value: ProviderValueMap.DigitalOcean,
|
||||
icon: <IconFont type="icon-digitalocean" />
|
||||
},
|
||||
{
|
||||
label: 'Kubernetes',
|
||||
locale: false,
|
||||
value: 'kubernetes',
|
||||
key: 'kubernetes',
|
||||
icon: <KubernetesOutlined className="size-16" />
|
||||
}
|
||||
];
|
||||
|
||||
@@ -80,7 +50,7 @@ const Credentials: React.FC = () => {
|
||||
} = useTableFetch<ListItem>({
|
||||
fetchAPI: queryCredentialList,
|
||||
deleteAPI: deleteCredential,
|
||||
contentForDelete: 'users.table.user'
|
||||
contentForDelete: 'menu.clusterManagement.credentials'
|
||||
});
|
||||
|
||||
const intl = useIntl();
|
||||
@@ -98,12 +68,17 @@ const Credentials: React.FC = () => {
|
||||
currentData: undefined
|
||||
});
|
||||
|
||||
const handleAddCredential = () => {
|
||||
const handleAddCredential = (item: { key: string; label: string }) => {
|
||||
setOpenModalStatus({
|
||||
provider: ProviderValueMap.DigitalOcean,
|
||||
provider: item.key,
|
||||
open: true,
|
||||
action: PageAction.CREATE,
|
||||
title: intl.formatMessage({ id: 'clusters.button.addCredential' }),
|
||||
title: intl.formatMessage(
|
||||
{ id: 'clusters.button.add.credential' },
|
||||
{
|
||||
provider: ProviderLabelMap[item.key] || item.key
|
||||
}
|
||||
),
|
||||
currentData: undefined
|
||||
});
|
||||
};
|
||||
@@ -132,8 +107,11 @@ const Credentials: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleModalCancel = () => {
|
||||
console.log('handleModalCancel');
|
||||
setOpenModalStatus({ ...openModalStatus, open: false });
|
||||
setOpenModalStatus({
|
||||
...openModalStatus,
|
||||
open: false,
|
||||
currentData: undefined
|
||||
});
|
||||
};
|
||||
|
||||
const handleEditUser = (row: ListItem) => {
|
||||
@@ -142,20 +120,20 @@ const Credentials: React.FC = () => {
|
||||
open: true,
|
||||
action: PageAction.EDIT,
|
||||
title: intl.formatMessage(
|
||||
{ id: 'common.buton.edit.item' },
|
||||
{ id: 'common.button.edit.item' },
|
||||
{ name: row.name }
|
||||
),
|
||||
currentData: row
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelect = (val: any, row: ListItem) => {
|
||||
const handleSelect = useMemoizedFn((val: any, row: ListItem) => {
|
||||
if (val === 'edit') {
|
||||
handleEditUser(row);
|
||||
} else if (val === 'delete') {
|
||||
handleDelete({ ...row, name: row.name });
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const renderEmpty = (type?: string) => {
|
||||
if (type !== 'Table') return;
|
||||
@@ -169,6 +147,8 @@ const Credentials: React.FC = () => {
|
||||
return <div></div>;
|
||||
};
|
||||
|
||||
const columns = useCredentialColumns(sortOrder, handleSelect);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageContainer
|
||||
@@ -185,6 +165,8 @@ const Credentials: React.FC = () => {
|
||||
extra={[]}
|
||||
>
|
||||
<FilterBar
|
||||
actionItems={addActions}
|
||||
actionType="dropdown"
|
||||
showSelect={false}
|
||||
showPrimaryButton={true}
|
||||
marginBottom={22}
|
||||
@@ -202,6 +184,8 @@ const Credentials: React.FC = () => {
|
||||
|
||||
<ConfigProvider renderEmpty={renderEmpty}>
|
||||
<Table
|
||||
tableLayout="fixed"
|
||||
columns={columns}
|
||||
dataSource={dataSource.dataList}
|
||||
rowSelection={rowSelection}
|
||||
loading={dataSource.loading}
|
||||
@@ -215,87 +199,7 @@ const Credentials: React.FC = () => {
|
||||
hideOnSinglePage: queryParams.perPage === 10,
|
||||
onChange: handlePageChange
|
||||
}}
|
||||
>
|
||||
<Column
|
||||
title={intl.formatMessage({ id: 'common.table.name' })}
|
||||
dataIndex="name"
|
||||
key="name"
|
||||
ellipsis={{
|
||||
showTitle: false
|
||||
}}
|
||||
render={(text, record) => {
|
||||
return (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{text}
|
||||
</AutoTooltip>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
title={intl.formatMessage({ id: 'clusters.table.provider' })}
|
||||
dataIndex="provider"
|
||||
key="provider"
|
||||
ellipsis={{
|
||||
showTitle: false
|
||||
}}
|
||||
render={(text, record) => {
|
||||
return (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{text}
|
||||
</AutoTooltip>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
title={intl.formatMessage({ id: 'common.table.createTime' })}
|
||||
dataIndex="created_at"
|
||||
key="createTime"
|
||||
defaultSortOrder="descend"
|
||||
sortOrder={sortOrder}
|
||||
showSorterTooltip={false}
|
||||
sorter={false}
|
||||
ellipsis={{
|
||||
showTitle: false
|
||||
}}
|
||||
render={(text, record) => {
|
||||
return (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</AutoTooltip>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
title={intl.formatMessage({ id: 'common.table.description' })}
|
||||
dataIndex="description"
|
||||
key="description"
|
||||
ellipsis={{
|
||||
showTitle: false
|
||||
}}
|
||||
render={(text, record) => {
|
||||
return (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{text}
|
||||
</AutoTooltip>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
title={intl.formatMessage({ id: 'common.table.operation' })}
|
||||
key="operation"
|
||||
ellipsis={{
|
||||
showTitle: false
|
||||
}}
|
||||
render={(text, record: ListItem) => {
|
||||
return (
|
||||
<DropdownButtons
|
||||
items={ActionList}
|
||||
onSelect={(val) => handleSelect(val, record)}
|
||||
></DropdownButtons>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
></Table>
|
||||
</ConfigProvider>
|
||||
</PageContainer>
|
||||
<AddModal
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// columns.ts
|
||||
import AutoTooltip from '@/components/auto-tooltip';
|
||||
import DropdownButtons from '@/components/drop-down-buttons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { ColumnsType } from 'antd/es/table';
|
||||
import type { SortOrder } from 'antd/es/table/interface';
|
||||
import dayjs from 'dayjs';
|
||||
import { useMemo } from 'react';
|
||||
import { ProviderLabelMap, credentialActionList } from '../config';
|
||||
import { CredentialListItem as ListItem } from '../config/types';
|
||||
|
||||
const useCredentialColumns = (
|
||||
sortOrder: SortOrder,
|
||||
handleSelect: (val: string, record: ListItem) => void
|
||||
): ColumnsType<ListItem> => {
|
||||
const intl = useIntl();
|
||||
|
||||
return useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||
dataIndex: 'name',
|
||||
render: (text: string) => (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{text}
|
||||
</AutoTooltip>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'clusters.table.provider' }),
|
||||
dataIndex: 'provider',
|
||||
render: (value: string) => <span>{ProviderLabelMap[value]}</span>
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'common.table.createTime' }),
|
||||
dataIndex: 'created_at',
|
||||
showSorterTooltip: false,
|
||||
defaultSortOrder: 'descend',
|
||||
sortOrder: sortOrder,
|
||||
sorter: false,
|
||||
ellipsis: {
|
||||
showTitle: false
|
||||
},
|
||||
render: (value: string) => (
|
||||
<span>{dayjs(value).format('YYYY-MM-DD HH:mm:ss')}</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'common.table.description' }),
|
||||
dataIndex: 'description',
|
||||
ellipsis: {
|
||||
showTitle: false
|
||||
},
|
||||
render: (value: string) => (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{value}
|
||||
</AutoTooltip>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'common.table.operation' }),
|
||||
dataIndex: 'operations',
|
||||
ellipsis: {
|
||||
showTitle: false
|
||||
},
|
||||
render: (value: string, record: ListItem) => (
|
||||
<DropdownButtons
|
||||
items={credentialActionList}
|
||||
onSelect={(val) => handleSelect(val, record)}
|
||||
></DropdownButtons>
|
||||
)
|
||||
}
|
||||
];
|
||||
}, [handleSelect, sortOrder]);
|
||||
};
|
||||
|
||||
export default useCredentialColumns;
|
||||
@@ -46,11 +46,11 @@ export const ActionList: ActionItem[] = [
|
||||
key: 'edit',
|
||||
icon: icons.EditOutlined
|
||||
},
|
||||
{
|
||||
label: 'common.button.detail',
|
||||
key: 'details',
|
||||
icon: icons.FileTextOutlined
|
||||
},
|
||||
// {
|
||||
// label: 'common.button.detail',
|
||||
// key: 'details',
|
||||
// icon: icons.FileTextOutlined
|
||||
// },
|
||||
{
|
||||
label: 'models.openinplayground',
|
||||
key: 'chat',
|
||||
|
||||
@@ -194,6 +194,10 @@ const LoginForm = () => {
|
||||
return SSOAuth.options.oidc || SSOAuth.options.saml;
|
||||
}, [SSOAuth.options]);
|
||||
|
||||
const isThirdPartyAuthHandling = useMemo(() => {
|
||||
return loading && !authError;
|
||||
}, [loading, authError]);
|
||||
|
||||
const renderLoginButtons = () => {
|
||||
// do not render login buttons if using password login or no third-party login
|
||||
if (!hasThirdPartyLogin || isPassword) return null;
|
||||
@@ -229,10 +233,6 @@ const LoginForm = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const isThirdPartyAuthHandling = useMemo(() => {
|
||||
return loading && !authError;
|
||||
}, [loading, authError]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{contextHolder}
|
||||
|
||||
@@ -67,4 +67,4 @@ const AddWorker: React.FC<ViewModalProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(AddWorker);
|
||||
export default AddWorker;
|
||||
|
||||
@@ -111,4 +111,4 @@ const UpdateLabels: React.FC<ViewModalProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(UpdateLabels);
|
||||
export default UpdateLabels;
|
||||
|
||||
@@ -63,6 +63,9 @@ const useGPUColumns = (props: {
|
||||
{
|
||||
title: intl.formatMessage({ id: 'clusters.title' }),
|
||||
dataIndex: 'cluster_id',
|
||||
ellipsis: {
|
||||
showTitle: false
|
||||
},
|
||||
render: (text: number, record: GPUDeviceItem) => (
|
||||
<AutoTooltip ghost>
|
||||
{clusterList.find((item) => item.value === text)?.label}
|
||||
@@ -70,8 +73,11 @@ const useGPUColumns = (props: {
|
||||
)
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'resources.table.workername' }),
|
||||
title: 'Worker',
|
||||
dataIndex: 'worker_name',
|
||||
ellipsis: {
|
||||
showTitle: false
|
||||
},
|
||||
render: (text: string, record: GPUDeviceItem) => (
|
||||
<AutoTooltip ghost>{text}</AutoTooltip>
|
||||
)
|
||||
|
||||
@@ -294,7 +294,7 @@ const useInstanceColumns = (props: {
|
||||
return useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||
title: intl.formatMessage({ id: 'resources.model.instance' }),
|
||||
dataIndex: 'name',
|
||||
width: 240,
|
||||
render: (text: string, record: ListItem) => (
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
CodeOutlined,
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
FileTextOutlined,
|
||||
InfoCircleOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
@@ -31,7 +32,7 @@ const ActionList = [
|
||||
{
|
||||
label: 'common.button.detail',
|
||||
key: 'details',
|
||||
icon: <IconFont type="icon-detail-info" />
|
||||
icon: <FileTextOutlined></FileTextOutlined>
|
||||
},
|
||||
{
|
||||
label: 'common.button.logs',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import _ from 'lodash';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
export const isNotEmptyValue = (value: any) => {
|
||||
if (Array.isArray(value)) {
|
||||
@@ -219,3 +220,22 @@ export const base64ToFile = (base64String: string, fileName: string) => {
|
||||
export const isOnline = () => {
|
||||
return window.navigator.onLine;
|
||||
};
|
||||
|
||||
export const genColors = ({
|
||||
color,
|
||||
alpha1,
|
||||
alpha2
|
||||
}: {
|
||||
color: string;
|
||||
alpha1?: number;
|
||||
alpha2?: number;
|
||||
}) => {
|
||||
const base = tinycolor(color);
|
||||
const alpha_start = alpha1 || base.getAlpha();
|
||||
const alpha_end = alpha2 || base.getAlpha();
|
||||
|
||||
return [
|
||||
base.setAlpha(alpha_start).toRgbString(),
|
||||
base.setAlpha(alpha_end).toRgbString()
|
||||
];
|
||||
};
|
||||
|
||||
Vendored
+1
@@ -26,5 +26,6 @@ declare module 'vibrant';
|
||||
declare module 'node-vibrant';
|
||||
declare module 'lamejs';
|
||||
declare module 'file-saver';
|
||||
declare module 'tinycolor2';
|
||||
|
||||
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
|
||||
|
||||
Reference in New Issue
Block a user