feat: add watch api in cluster

This commit is contained in:
jialin
2025-09-16 11:26:17 +08:00
parent 07ade24ea1
commit deeee70807
34 changed files with 706 additions and 229 deletions
@@ -2,6 +2,7 @@ import ModalFooter from '@/components/modal-footer';
import ScrollerModal from '@/components/scroller-modal/index';
import { PageActionType } from '@/config/types';
import React, { useRef } from 'react';
import { ProviderType } from '../config';
import {
ClusterFormData as FormData,
ClusterListItem as ListItem
@@ -13,7 +14,7 @@ type AddModalProps = {
action: PageActionType;
open: boolean;
currentData?: ListItem; // Used when action is EDIT
provider: string;
provider: ProviderType;
credentialList: Global.BaseOption<number>[];
onOk: (values: FormData) => void;
onCancel: () => void;
@@ -20,10 +20,10 @@ type AddModalProps = {
const AddWorkerStep: React.FC<AddModalProps> = ({ registrationInfo }) => {
return (
<div>
<Title>Supported Hardware Platforms</Title>
<SupportedHardware />
<Title style={{ marginTop: 32 }}>Execute Command</Title>
<Title>Execute Command</Title>
<RegisterClusterInner registrationInfo={registrationInfo} />
<Title style={{ marginTop: 32 }}>Supported GPUs</Title>
<SupportedHardware />
</div>
);
};
@@ -92,12 +92,7 @@ const CloudProvider: React.FC<CloudProviderProps> = (props) => {
rules={[
{
required: true,
message: intl.formatMessage(
{ id: 'common.form.rule.input' },
{
name: 'credential'
}
)
message: getRuleMessage('input', 'clusters.credential.title')
}
]}
>
@@ -5,14 +5,24 @@ import styled from 'styled-components';
const { Step } = Steps;
const Wrapper = styled.div`
padding-block: 20px;
padding-block: 30px;
background-color: var(--ant-color-bg-container);
.ant-steps-item-description {
max-width: 300px !important;
color: var(--ant-color-text-description) !important;
}
.ant-steps-item-content > .ant-steps-item-title {
font-weight: 600;
// font-weight: 600;
}
.ant-steps-item {
.ant-steps-item-container {
// .ant-steps-item-icon {
// margin-inline-start: 0 !important;
// }
// .ant-steps-item-tail {
// margin-inline-start: 0 !important;
// }
}
}
`;
@@ -25,7 +35,7 @@ const ClusterSteps: React.FC<{
return (
<Wrapper>
<Steps current={currentStep} size="small" onChange={onChange}>
<Steps current={currentStep} size="small" onChange={onChange} progressDot>
{steps.map((step) => (
<Step
disabled={step.disabled}
@@ -29,6 +29,9 @@ const Container = styled.div`
.ant-form-item:nth-child(6) {
grid-column: 1 / 3;
}
.ant-form-item:nth-child(7) {
grid-column: 1 / 3;
}
`;
type AddModalProps = {
@@ -57,7 +60,7 @@ const PoolForm: React.FC<AddModalProps> = forwardRef((props, ref) => {
const intl = useIntl();
const { getRuleMessage } = useAppUtils();
const labels = Form.useWatch('labels', form);
const instance_type = Form.useWatch('instance_type', form);
const title = Form.useWatch('name', form);
useEffect(() => {
if (currentData) {
@@ -88,13 +91,12 @@ const PoolForm: React.FC<AddModalProps> = forwardRef((props, ref) => {
return (
<CollapsibleContainer
title={instance_type}
{...restCollapseProps}
title={title}
collapsible={collapsible}
onToggle={onToggle}
{...restCollapseProps}
>
{showDelete && (
<div className="flex-end" style={{ marginBlock: '8px 16px' }}>
deleteBtn={
showDelete && (
<Button
onClick={onDelete}
icon={<DeleteOutlined />}
@@ -104,8 +106,9 @@ const PoolForm: React.FC<AddModalProps> = forwardRef((props, ref) => {
color="danger"
size="small"
></Button>
</div>
)}
)
}
>
<Form
name={name}
form={form}
@@ -118,6 +121,22 @@ const PoolForm: React.FC<AddModalProps> = forwardRef((props, ref) => {
}}
>
<Container>
<Form.Item<FormData>
name="name"
rules={[
{
required: true,
message: getRuleMessage('input', 'common.table.name')
}
]}
>
<SealInput.Input
label={intl.formatMessage({
id: 'common.table.name'
})}
required
></SealInput.Input>
</Form.Item>
<Form.Item<FormData>
name="instance_type"
rules={[
@@ -135,6 +154,7 @@ const PoolForm: React.FC<AddModalProps> = forwardRef((props, ref) => {
id: 'clusters.workerpool.instanceType'
})}
required
disabled={action === PageAction.EDIT}
></SealInput.Input>
</Form.Item>
<Form.Item<FormData>
@@ -1,5 +1,7 @@
import DeleteModal from '@/components/delete-modal';
import CellContent from '@/components/seal-table/components/cell-content';
import RowChildren from '@/components/seal-table/components/row-children';
import RowContext from '@/components/seal-table/row-context';
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
import { useIntl } from '@umijs/max';
@@ -11,7 +13,6 @@ import { ProviderType } from '../config';
import { NodePoolFormData, NodePoolListItem } from '../config/types';
import usePoolsColumns from '../hooks/use-pools-columns';
import AddPool from './add-pool';
interface PoolRowsProps {
dataList: NodePoolListItem[];
provider: ProviderType;
@@ -58,6 +59,18 @@ const PoolRows: React.FC<PoolRowsProps> = ({
}
};
const handleOnCell = async (row: NodePoolListItem, dataIndex: string) => {
console.log('handleOncell===', row, dataIndex);
try {
await updateWorkerPool({
data: row,
id: row.id
});
message.success(intl.formatMessage({ id: 'common.message.success' }));
} catch (error) {
// error
}
};
const handleEdit = (action: string, record: NodePoolListItem) => {
if (action === 'edit') {
setAddPoolStatus({
@@ -97,6 +110,7 @@ const PoolRows: React.FC<PoolRowsProps> = ({
});
const columns = usePoolsColumns(onSelect);
return (
<>
{dataList?.map((data: NodePoolListItem) => {
@@ -105,23 +119,32 @@ const PoolRows: React.FC<PoolRowsProps> = ({
key={data.id}
style={{ borderRadius: 'var(--ant-table-header-border-radius)' }}
>
<RowChildren>
<Row style={{ width: '100%' }} align="middle">
{columns.map((col: Record<string, any>) => {
return (
<Col
key={col.dataIndex as string}
span={col.span}
style={col.style}
>
{col.render
<RowContext.Provider value={{ row: data, onCell: handleOnCell }}>
<RowChildren>
<Row style={{ width: '100%' }} align="middle">
{columns.map((col: Record<string, any>) => {
return (
<Col
key={col.dataIndex as string}
span={col.span}
style={{
paddingInline: 0,
...(col.style || {})
}}
>
{/* {col.render
? col.render(data[col.dataIndex as string], data)
: data[col.dataIndex as string]}
</Col>
);
})}
</Row>
</RowChildren>
: data[col.dataIndex as string]} */}
<CellContent
{...col}
dataIndex={col.dataIndex}
></CellContent>
</Col>
);
})}
</Row>
</RowChildren>
</RowContext.Provider>
</div>
);
})}
@@ -21,7 +21,7 @@ const Title = styled.span`
align-items: center;
justify-content: space-between;
font-weight: 700;
font-size: 18px;
font-size: 16px;
margin-block: 16px 24px;
`;
@@ -13,10 +13,9 @@ const ProviderImage = ({ src, showBg }: { src: string; showBg?: boolean }) => {
<img
src={src}
style={{
width: 46,
width: 32,
objectFit: 'contain'
}}
width={46}
/>
);
};
@@ -37,7 +36,7 @@ const supportedHardPlatforms = [
icon: (
<IconFont
type="icon-amd"
style={{ fontSize: 46, color: 'var(--ant-color-text)' }}
style={{ fontSize: 32, color: 'var(--ant-color-text)' }}
/>
)
},
@@ -14,7 +14,7 @@ import {
updateWorkerPool,
WORKER_POOLS_API
} from '../apis';
import { ProviderValueMap } from '../config';
import { ProviderType, ProviderValueMap } from '../config';
import {
NodePoolListItem as ListItem,
NodePoolFormData
@@ -60,7 +60,7 @@ const WorkerPools = () => {
open: false,
action: PageAction.CREATE,
title: '',
provider: ProviderValueMap.DigitalOcean,
provider: ProviderValueMap.DigitalOcean as ProviderType,
currentData: null as ListItem | null,
clusterId: 0 as number | string
});
@@ -75,7 +75,7 @@ const WorkerPools = () => {
{ id: 'common.button.edit.item' },
{ name: record.instance_type }
),
provider: searchParams.get('provider') || '',
provider: searchParams.get('provider') as ProviderType,
currentData: record,
clusterId: searchParams.get('id') || 0
});
@@ -87,7 +87,7 @@ const WorkerPools = () => {
open: true,
action: PageAction.CREATE,
title: intl.formatMessage({ id: 'clusters.button.addNodePool' }),
provider: searchParams.get('provider') || '',
provider: searchParams.get('provider') as ProviderType,
clusterId: searchParams.get('id') || 0,
currentData: null
});
@@ -177,7 +177,7 @@ const WorkerPools = () => {
open: false,
action: PageAction.CREATE,
title: '',
provider: ProviderValueMap.DigitalOcean,
provider: ProviderValueMap.DigitalOcean as ProviderType,
currentData: null,
clusterId: 0
});