refactor: credential table columns

This commit is contained in:
jialin
2025-09-16 11:26:17 +08:00
parent 43936e21d9
commit 0c1057d554
34 changed files with 648 additions and 503 deletions
+2 -1
View File
@@ -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"
+344 -304
View File
File diff suppressed because it is too large Load Diff
+19 -12
View File
@@ -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]) => [
+20
View File
@@ -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 {
+21
View File
@@ -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]
// }
// ])
// }
};
});
+1
View File
@@ -45,6 +45,7 @@ const ScrollerModal = (props: ModalProps & { maxContentHeight?: number }) => {
return (
<Modal
{...props}
destroyOnClose={true}
styles={{
content: {
padding: 0
+4 -4
View File
@@ -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({
+2 -1
View File
@@ -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'
};
+2 -1
View File
@@ -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'
};
+4 -2
View File
@@ -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 ==========
+3 -1
View File
@@ -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 ==========
+4 -2
View File
@@ -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 ==========
+2 -1
View File
@@ -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) ==========
+2 -1
View File
@@ -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} 凭证'
};
+2 -1
View File
@@ -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': '模型实例'
};
+1 -1
View File
@@ -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,
+17 -1
View File
@@ -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',
+29 -125
View File
@@ -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;
+5 -5
View File
@@ -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',
+4 -4
View File
@@ -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',
+20
View File
@@ -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()
];
};
+1
View File
@@ -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;