diff --git a/src/hooks/use-table-fetch.ts b/src/hooks/use-table-fetch.ts index 9f6caf5b..7cbf2f83 100644 --- a/src/hooks/use-table-fetch.ts +++ b/src/hooks/use-table-fetch.ts @@ -179,6 +179,7 @@ export default function useTableFetch( }, 5000); }; + // for selection change const handleQueryChange = (params: any) => { setQueryParams({ ...queryParams, diff --git a/src/pages/cluster-management/apis/index.ts b/src/pages/cluster-management/apis/index.ts index 6bcba5b0..70f0a3d3 100644 --- a/src/pages/cluster-management/apis/index.ts +++ b/src/pages/cluster-management/apis/index.ts @@ -1,3 +1,4 @@ +import { DASHBOARD_API } from '@/pages/dashboard/apis'; import { request } from '@umijs/max'; import { ClusterFormData, @@ -83,9 +84,10 @@ export async function deleteCluster(id: number) { }); } -export async function queryClusterDetail(id: number) { - return request(`${CLUSTERS_API}/${id}`, { - method: 'GET' +export async function queryClusterDetail(params: { cluster_id: number }) { + return request(`${DASHBOARD_API}`, { + method: 'GET', + params }); } diff --git a/src/pages/cluster-management/clusters.tsx b/src/pages/cluster-management/clusters.tsx index 77629cfe..45356e87 100644 --- a/src/pages/cluster-management/clusters.tsx +++ b/src/pages/cluster-management/clusters.tsx @@ -1,7 +1,5 @@ import DeleteModal from '@/components/delete-modal'; import { FilterBar } from '@/components/page-tools'; -import CardList from '@/components/templates/card-list'; -import CardSkeleton from '@/components/templates/card-skelton'; import { PageAction } from '@/config'; import type { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; @@ -19,20 +17,19 @@ import { } from './apis'; import AddCluster from './components/add-cluster'; import ClusterDetailModal from './components/cluster-detail-modal'; -import ClusterItem from './components/cluster-item'; +import RegisterCluster from './components/register-cluster'; import { ProviderLabelMap, ProviderValueMap, addActions } from './config'; import { ClusterFormData as FormData, ClusterListItem as ListItem } from './config/types'; -const { Column } = Table; +import useClusterColumns from './config/use-cluster-columns'; const Credentials: React.FC = () => { const { dataSource, rowSelection, queryParams, - sortOrder, modalRef, handleDelete, handleDeleteBatch, @@ -48,12 +45,29 @@ const Credentials: React.FC = () => { }); const intl = useIntl(); - const [openClusterDetail, setOpenClusterDetail] = useState<{ + const [registerClusterStatus, setRegisterClusterStatus] = useState<{ open: boolean; - id: number; + registrationInfo: { + token: string; + image: string; + server_url: string; + cluster_id: number; + }; }>({ open: false, - id: 0 + registrationInfo: { + token: '', + image: '', + server_url: '', + cluster_id: 0 + } + }); + const [openClusterDetail, setOpenClusterDetail] = useState<{ + open: boolean; + currentData: ListItem | null; + }>({ + open: false, + currentData: {} as ListItem }); const [openAddWorker, setOpenAddWorker] = useState<{ open: boolean; @@ -187,6 +201,19 @@ const Credentials: React.FC = () => { } }; + const handleRegisterCluster = async (row: ListItem) => { + try { + const info = await queryClusterToken({ id: row.id }); + setRegisterClusterStatus({ + open: true, + registrationInfo: { + ...info, + cluster_id: row.id + } + }); + } catch (error) {} + }; + const handleSelect = (val: any, row: ListItem) => { if (val === 'edit') { handleEditCluster(row); @@ -199,14 +226,14 @@ const Credentials: React.FC = () => { } else if (val === 'details') { setOpenClusterDetail({ open: true, - id: row.id + currentData: row }); + } else if (val === 'register_cluster') { + handleRegisterCluster(row); } }; - const renderCard = (item: ListItem) => { - return ; - }; + const columns = useClusterColumns(handleSelect); return ( <> @@ -230,24 +257,34 @@ const Credentials: React.FC = () => { selectHolder="Filter by name" marginBottom={22} marginTop={30} - handleInputChange={handleNameChange} - handleSearch={handleSearch} width={{ input: 300 }} buttonText="Add Cluster" actionType="dropdown" actionItems={addActions} + rowSelection={rowSelection} + handleInputChange={handleNameChange} + handleSearch={handleSearch} + handleDeleteByBatch={handleDeleteBatch} handleClickPrimary={handleClickDropdown} > - + rowSelection={rowSelection} + columns={columns} + pagination={{ + showSizeChanger: true, + pageSize: queryParams.perPage, + current: queryParams.page, + total: dataSource.total, + hideOnSinglePage: queryParams.perPage === 10, + onChange: handlePageChange + }} + > { > setOpenClusterDetail({ open: false, id: 0 })} + currentData={openClusterDetail.currentData} + onClose={() => + setOpenClusterDetail({ open: false, currentData: {} as ListItem }) + } > + { + setRegisterClusterStatus({ + open: false, + registrationInfo: { + token: '', + image: '', + server_url: '', + cluster_id: 0 + } + }); + }} + > ); diff --git a/src/pages/cluster-management/components/add-cluster.tsx b/src/pages/cluster-management/components/add-cluster.tsx index a6a63251..4d8f6680 100644 --- a/src/pages/cluster-management/components/add-cluster.tsx +++ b/src/pages/cluster-management/components/add-cluster.tsx @@ -45,7 +45,6 @@ const AddCluster: React.FC = ({ }; const handleOk = async (data: FormData) => { - console.log('handleOk===', data); onOk({ ...data, provider @@ -59,17 +58,14 @@ const AddCluster: React.FC = ({ const renderAddWorkerContent = () => { if (provider === ProviderValueMap.Custom) { - return ; + return ; } if (provider === ProviderValueMap.Kubernetes) { - return ( - - ); + return ; } return null; }; + const modalTitle = useMemo(() => { if (submissionStatus.success) { return ( diff --git a/src/pages/cluster-management/components/cluster-detail-content.tsx b/src/pages/cluster-management/components/cluster-detail-content.tsx index d64347c0..959e724f 100644 --- a/src/pages/cluster-management/components/cluster-detail-content.tsx +++ b/src/pages/cluster-management/components/cluster-detail-content.tsx @@ -1,8 +1,9 @@ import GaugeChart from '@/components/echarts/gauge'; import { PageAction } from '@/config'; import { Col, Row } from 'antd'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import styled from 'styled-components'; +import { queryClusterDetail } from '../apis'; import { ProviderValueMap } from '../config'; import { ClusterListItem, NodePoolListItem } from '../config/types'; import AddPool from './add-pool'; @@ -16,7 +17,7 @@ const SubTitle = styled.div` `; interface ClusterDetailProps { - data: ClusterListItem; + data: ClusterListItem | null; } const gaugeConfig = { @@ -46,8 +47,9 @@ const ClusterDetail: React.FC = ({ data }) => { open: false, action: PageAction.CREATE, title: '', - provider: 'digitalocean' + provider: ProviderValueMap.DigitalOcean }); + const [detailContent, setDetailContent] = useState>({}); // pool action handler const handleOnAction = (action: string, record: NodePoolListItem) => { @@ -56,11 +58,32 @@ const ClusterDetail: React.FC = ({ data }) => { open: true, action: PageAction.CREATE, title: 'Edit Worker Pool', - provider: data.provider + provider: data!.provider }); } }; + const getClusterDetail = async () => { + if (!data) { + return; + } + try { + const response = await queryClusterDetail({ + cluster_id: data!.id + }); + setDetailContent(response); + // handle response + } catch (error) { + setDetailContent({}); + } + }; + + useEffect(() => { + if (data?.id) { + getClusterDetail(); + } + }, [data?.id]); + return (
@@ -99,12 +122,12 @@ const ClusterDetail: React.FC = ({ data }) => {
- {data.provider === ProviderValueMap.DigitalOcean && ( + {data?.provider === ProviderValueMap.DigitalOcean && ( <> Worker Pools diff --git a/src/pages/cluster-management/components/cluster-detail-modal.tsx b/src/pages/cluster-management/components/cluster-detail-modal.tsx index 7718cf42..c4e9a6c5 100644 --- a/src/pages/cluster-management/components/cluster-detail-modal.tsx +++ b/src/pages/cluster-management/components/cluster-detail-modal.tsx @@ -1,27 +1,19 @@ import GSDrawer from '@/components/scroller-modal/gs-drawer'; import React from 'react'; +import { ClusterListItem } from '../config/types'; import ClusterDetailContent from './cluster-detail-content'; interface ClusterDetailModalProps { open: boolean; onClose?: () => void; - id: number; + currentData: ClusterListItem | null; } const ClusterDetailModal: React.FC = ({ open, onClose, - id: clusterId + currentData = {} as ClusterListItem }) => { - const [data, setData] = React.useState({ - id: 2, - name: 'Digital-Ocean-cluster', - provider: 'digitalocean', - workers: 3, - gpus: 6, - status: 'error', - deployments: 2 - }); const handleOnClose = () => { onClose?.(); }; @@ -29,11 +21,11 @@ const ClusterDetailModal: React.FC = ({ return ( - + ); }; diff --git a/src/pages/cluster-management/components/cluster-item.tsx b/src/pages/cluster-management/components/cluster-item.tsx index 82ed4cf8..b33c6c64 100644 --- a/src/pages/cluster-management/components/cluster-item.tsx +++ b/src/pages/cluster-management/components/cluster-item.tsx @@ -14,7 +14,7 @@ import { ClusterStatusLabelMap, ProviderLabelMap, ProviderValueMap, - poolActionList + clusterActionList } from '../config'; import { ClusterListItem as ListItem, NodePoolListItem } from '../config/types'; import AddPool from './add-pool'; @@ -225,7 +225,7 @@ const CardItem: React.FC = (props) => { }; const actions = useMemo(() => { - return poolActionList.filter((item) => { + return clusterActionList.filter((item) => { if (item.provider) { return item.provider === data.provider; } diff --git a/src/pages/cluster-management/components/resiter-cluster-inner.tsx b/src/pages/cluster-management/components/resiter-cluster-inner.tsx index 82ca11b2..186d5ff4 100644 --- a/src/pages/cluster-management/components/resiter-cluster-inner.tsx +++ b/src/pages/cluster-management/components/resiter-cluster-inner.tsx @@ -1,20 +1,7 @@ import HighlightCode from '@/components/highlight-code'; import React, { useMemo } from 'react'; -import styled from 'styled-components'; import { generateRegisterCommand } from '../config'; -const Title = styled.h3` - font-weight: 600; - color: var(--ant-color-text); - margin-bottom: 12px; - margin-top: 12px; - font-size: var(--font-size-normal); - .ant-tag { - color: var(--ant-color-text-secondary); - font-weight: 400; - } -`; - type AddModalProps = { registrationInfo: { token: string; @@ -32,10 +19,6 @@ const AddCluster: React.FC = ({ registrationInfo }) => { }); }, [registrationInfo]); - const applyCommand = useMemo(() => { - return `kubectl apply -f manifest.yaml`; - }, []); - return (
void +): ColumnsType => { + const setActionsItems = (row: ClusterListItem) => { + return clusterActionList.filter((item) => { + if (item.provider) { + return item.provider === row.provider; + } + return true; + }); + }; + + return useMemo(() => { + return [ + { + title: 'Name', + dataIndex: 'name', + render: (text: string) => {text} + }, + { + title: 'Provider', + dataIndex: 'provider', + render: (value: string) => {ProviderLabelMap[value]} + }, + { + title: 'Status', + dataIndex: 'state', + render: (value: number) => ( + + ) + }, + { + title: 'Workers', + dataIndex: 'workers', + render: (value: number) => {value} + }, + { + title: 'GPUs', + dataIndex: 'gpus', + render: (value: number) => {value} + }, + { + title: 'Deployments', + dataIndex: 'models', + render: (value: number) => {value} + }, + { + title: 'Created', + dataIndex: 'created_at', + width: 180, + render: (value: string) => ( + {dayjs(value).format('YYYY-MM-DD HH:mm:ss')} + ) + }, + { + title: 'Operations', + dataIndex: 'operations', + render: (value: string, record: ClusterListItem) => ( + handleSelect(val, record)} + > + ) + } + ]; + }, [handleSelect]); +}; + +export default useClusterColumns; diff --git a/src/pages/resources/components/container-install.tsx b/src/pages/resources/components/container-install.tsx index 51d86580..027c7384 100644 --- a/src/pages/resources/components/container-install.tsx +++ b/src/pages/resources/components/container-install.tsx @@ -133,4 +133,4 @@ const AddWorker: React.FC = (props) => { ); }; -export default React.memo(AddWorker); +export default AddWorker;