style: cluster advanced scroller

This commit is contained in:
jialin
2025-12-18 20:03:00 +08:00
parent e1b8b5696c
commit 14d944ad2f
5 changed files with 66 additions and 17 deletions
@@ -1,6 +1,6 @@
import { useScrollerContext } from '@/components/scroller-modal/use-scroller-context';
import SealInput from '@/components/seal-form/seal-input'; import SealInput from '@/components/seal-form/seal-input';
import SealTextArea from '@/components/seal-form/seal-textarea'; import SealTextArea from '@/components/seal-form/seal-textarea';
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types'; import { PageActionType } from '@/config/types';
import CollapsePanel from '@/pages/_components/collapse-panel'; import CollapsePanel from '@/pages/_components/collapse-panel';
import { json2Yaml, yaml2Json } from '@/pages/backends/config'; import { json2Yaml, yaml2Json } from '@/pages/backends/config';
@@ -25,7 +25,6 @@ type AddModalProps = {
}; };
const ClusterForm: React.FC<AddModalProps> = forwardRef( const ClusterForm: React.FC<AddModalProps> = forwardRef(
({ action, provider, currentData, credentialList, onFinish }, ref) => { ({ action, provider, currentData, credentialList, onFinish }, ref) => {
const { scrollToBottom } = useScrollerContext();
const [form] = Form.useForm(); const [form] = Form.useForm();
const intl = useIntl(); const intl = useIntl();
const [activeKey, setActiveKey] = React.useState<string[]>([]); const [activeKey, setActiveKey] = React.useState<string[]>([]);
@@ -33,14 +32,21 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
const handleOnCollapseChange = async (keys: string | string[]) => { const handleOnCollapseChange = async (keys: string | string[]) => {
setActiveKey(Array.isArray(keys) ? keys : [keys]); setActiveKey(Array.isArray(keys) ? keys : [keys]);
if (keys?.includes?.('advanceConfig')) {
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
scrollToBottom();
}
}; };
useEffect(() => {
if (
activeKey?.includes?.('advanceConfig') &&
action === PageAction.EDIT
) {
const el = document.querySelector('.scroller-to-holder');
if (!el) return;
setTimeout(() => {
el.scrollIntoView({ behavior: 'smooth' });
}, 300);
}
}, [activeKey, action]);
const handleOnFinish = (values: FormData) => { const handleOnFinish = (values: FormData) => {
const workerConfig = yaml2Json(advanceConfigRef.current?.getYamlValue()); const workerConfig = yaml2Json(advanceConfigRef.current?.getYamlValue());
@@ -256,7 +256,7 @@ const PoolForm: React.FC<AddModalProps> = forwardRef((props, ref) => {
const handleOsImageChange = (value: string, option: any) => { const handleOsImageChange = (value: string, option: any) => {
form.setFieldsValue({ form.setFieldsValue({
os_image: option.os_image || value os_image: option?.os_image || value
}); });
}; };
@@ -89,6 +89,7 @@ const ClusterAdvanceConfig: React.FC<{
}} }}
schema={schema} schema={schema}
></YamlEditor> ></YamlEditor>
<div className="scroller-to-holder" style={{ height: 1 }}></div>
</> </>
); );
}); });
@@ -116,8 +116,13 @@ const WorkerPoolsForm = forwardRef((props: WorkerPoolsFormProps, ref) => {
form?.validateFields() form?.validateFields()
); );
const results = await Promise.allSettled(promises); const results = await Promise.allSettled(promises);
console.log('results========0', promises, results); const rejectIndex = results.findIndex(
if (results.some((result) => result.status === 'rejected')) { (result) => result.status === 'rejected'
);
if (rejectIndex !== -1) {
setActiveKey(() => {
return new Set([rejectIndex]);
});
return Promise.reject({ return Promise.reject({
values: { values: {
worker_pools: gatherFormValues(results) worker_pools: gatherFormValues(results)
@@ -18,9 +18,27 @@ import { Tooltip } from 'antd';
import { ColumnsType } from 'antd/lib/table'; import { ColumnsType } from 'antd/lib/table';
import _ from 'lodash'; import _ from 'lodash';
import { useMemo } from 'react'; import { useMemo } from 'react';
import styled from 'styled-components';
import { status, WorkerStatusMap, WorkerStatusMapValue } from '../config'; import { status, WorkerStatusMap, WorkerStatusMapValue } from '../config';
import { Filesystem, GPUDeviceItem, ListItem } from '../config/types'; import { Filesystem, GPUDeviceItem, ListItem } from '../config/types';
const IPWrapper = styled.span`
display: flex;
flex-direction: column;
.item {
display: grid;
grid-template-columns: auto 1fr;
gap: 4px 8px;
.label {
text-align: right;
font-size: 13px;
display: flex;
align-items: center;
color: var(--ant-color-text-tertiary);
}
}
`;
const ActionList = [ const ActionList = [
{ label: 'common.button.edit', key: 'edit', icon: <EditOutlined /> }, { label: 'common.button.edit', key: 'edit', icon: <EditOutlined /> },
// { // {
@@ -229,6 +247,30 @@ const useWorkerColumns = ({
}): ColumnsType<ListItem> => { }): ColumnsType<ListItem> => {
const intl = useIntl(); const intl = useIntl();
const renderIP = (text: string, record: ListItem) => {
if (record.advertise_address === record.ip) {
return record.ip;
}
if (
record.advertise_address !== record.ip &&
record.advertise_address &&
record.ip
) {
return (
<IPWrapper>
<span className="item">
<span>{record.ip}</span>
<span className="label">{`(${intl.formatMessage({ id: 'clusters.table.ip.internal' })})`}</span>
<span> {record.advertise_address}</span>
<span className="label">{`(${intl.formatMessage({ id: 'clusters.table.ip.external' })})`}</span>
</span>
</IPWrapper>
);
}
return record.ip || record.advertise_address || '';
};
return useMemo<ColumnsType<ListItem>>( return useMemo<ColumnsType<ListItem>>(
() => [ () => [
{ {
@@ -281,12 +323,7 @@ const useWorkerColumns = ({
dataIndex: 'ip', dataIndex: 'ip',
render: (text: string, record) => ( render: (text: string, record) => (
<AutoTooltip ghost maxWidth={240}> <AutoTooltip ghost maxWidth={240}>
{record.advertise_address || text} {renderIP(text, record)}
{record.advertise_address
? ` (${intl.formatMessage({ id: 'clusters.table.ip.external' })})`
: record.ip
? ` (${intl.formatMessage({ id: 'clusters.table.ip.internal' })})`
: ''}
</AutoTooltip> </AutoTooltip>
) )
}, },