Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 66 additions & 3 deletions src/components/CreateComponentModal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import RbdPluginsCom from '../RBDPluginsCom';
import AppMarketContent from '../AppMarketContent';
import ImageNameForm from '../ImageNameForm';
import ImageComposeForm from '../ImageComposeForm';
import ImageVirtualMachineForm from '../ImageVirtualMachineForm';
import AddOrEditImageRegistry from '../AddOrEditImageRegistry';
import OauthForm from '../OauthForm';
import CodeCustomForm from '../CodeCustomForm';
Expand Down Expand Up @@ -106,6 +107,7 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
const [loadingDatabaseInfo, setLoadingDatabaseInfo] = useState(false);
const [currentDatabaseType, setCurrentDatabaseType] = useState(null);
const [showDatabaseForm, setShowDatabaseForm] = useState(false);
const [virtualMachineImages, setVirtualMachineImages] = useState([]);

// 插件相关状态
const [availablePlugins, setAvailablePlugins] = useState([]);
Expand Down Expand Up @@ -160,6 +162,7 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
const thirdPartyFormRef = useRef(null);
const thirdListFormRef = useRef(null);
const databaseFormRef = useRef(null);
const vmFormRef = useRef(null);
const marketInstallFormRef = useRef(null);
const localInstallFormRef = useRef(null);
const imageRepoFormRef = useRef(null);
Expand Down Expand Up @@ -880,8 +883,9 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
...(showVmEntry ? [{
iconSrc: InstalledVmIcon,
title: formatMessage({ id: 'componentOverview.body.CreateComponentModal.vm' }),
key: 'vm-display',
displayOnly: true,
key: 'vm',
showForm: true,
formType: 'vm',
iconColor: '#fa8c16',
}] : []),
...(showLlmEntry ? [{
Expand Down Expand Up @@ -1139,6 +1143,29 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
});
};

const fetchVirtualMachineImages = () => {
const teamName = globalUtil.getCurrTeamName();

if (!teamName) {
setVirtualMachineImages([]);
return;
}

dispatch({
type: 'createApp/getAppByVirtualMachineImage',
payload: {
team_name: teamName
},
callback: data => {
setVirtualMachineImages((data && data.list) || []);
},
handleError: err => {
setVirtualMachineImages([]);
handleAPIError(err);
Comment on lines +1160 to +1164
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetchVirtualMachineImages passes a handleError callback, but createApp/getAppByVirtualMachineImage currently delegates to getAppByVirtualMachineImage in src/services/createApp.js, which does not forward handleError to request(...). As a result, this handleError branch (and the setVirtualMachineImages([]) reset) will never run, and the UI may keep showing stale VM images after a failed request. Fix by updating the service (or model effect) to propagate/catch errors and invoke the provided handleError callback.

Copilot uses AI. Check for mistakes.
}
});
};

// 监听滚动事件进行自动加载 - 商店应用
useEffect(() => {
if (currentView !== 'marketStore') {
Expand Down Expand Up @@ -1283,8 +1310,11 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
if (visible && currentView === 'form') {
fetchLocalImageList();
fetchArchInfo();
if (currentFormType === 'vm') {
fetchVirtualMachineImages();
}
}
Comment on lines +1313 to 1316
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This effect now depends on currentFormType, so switching between different create forms while the modal is open will re-run fetchLocalImageList() and fetchArchInfo() each time (extra network calls even when those results are unchanged). Consider splitting VM-image loading into its own useEffect (triggered only when entering vm) so fetchLocalImageList/fetchArchInfo stay tied to [visible, currentView].

Suggested change
if (currentFormType === 'vm') {
fetchVirtualMachineImages();
}
}
}
}, [visible, currentView]);
useEffect(() => {
if (visible && currentView === 'form' && currentFormType === 'vm') {
fetchVirtualMachineImages();
}

Copilot uses AI. Check for mistakes.
}, [visible, currentView]);
}, [visible, currentView, currentFormType]);

// 当弹窗打开时,获取可用插件
useEffect(() => {
Expand Down Expand Up @@ -1709,6 +1739,25 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
});
} else if (currentFormType === 'database') {
dispatch(routerRedux.push(`/team/${teamName}/region/${regionName}/create/database-config/?database_type=${currentDatabaseType}&group_id=${value.group_id}&k8s_component_name=${value.k8s_component_name}&service_cname=${value.service_cname}`));
} else if (currentFormType === 'vm') {
dispatch({
type: 'createApp/createAppByVirtualMachine',
payload: {
team_name: teamName,
event_id,
...value
},
callback: data => {
if (data) {
const appAlias = data.bean.service_alias;
dispatch(routerRedux.push(`/team/${teamName}/region/${regionName}/create/create-check/${appAlias}`));
onCancel();
}
},
handleError: err => {
handleAPIError(err);
}
});
} else if (currentFormType === 'code-custom') {
// 源码提交
const username = value.username_1;
Expand Down Expand Up @@ -1980,6 +2029,7 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
if (currentFormType === 'helm') return formatMessage({ id: 'componentOverview.body.CreateComponentModal.helm' });
if (currentFormType === 'third-party') return formatMessage({ id: 'componentOverview.body.CreateComponentModal.third_party' });
if (currentFormType === 'database') return formatMessage({ id: 'componentOverview.body.CreateComponentModal.database' });
if (currentFormType === 'vm') return formatMessage({ id: 'componentOverview.body.CreateComponentModal.vm' });
return formatMessage({ id: 'componentOverview.body.CreateComponentModal.create_component' });
default:
return formatMessage({ id: 'componentOverview.body.CreateComponentModal.create_component' });
Expand Down Expand Up @@ -2138,6 +2188,9 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
case 'database':
formRef = databaseFormRef.current;
break;
case 'vm':
formRef = vmFormRef.current;
break;
default:
break;
}
Expand Down Expand Up @@ -2447,6 +2500,16 @@ const CreateComponentModal = ({ visible, onCancel, dispatch, currentEnterprise,
groupId={globalUtil.getAppID()}
/>
)}
{currentFormType === 'vm' && (
<ImageVirtualMachineForm
wrappedComponentRef={vmFormRef}
onSubmit={handleInstallApp}
dispatch={dispatch}
archInfo={archInfo}
virtualMachineImage={virtualMachineImages}
showSubmitBtn={false}
/>
)}
</div>
) : (
<>
Expand Down
5 changes: 4 additions & 1 deletion src/components/ImageVirtualMachineForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,15 @@ export default class Index extends PureComponent {
arch = archInfo && archInfo[0]
}
const group_id = globalUtil.getAppID()
const initialGroupId = isService
? Number(groupId)
: data.group_id || (group_id ? Number(group_id) : undefined)
return (
<Fragment>
<Form onSubmit={this.handleSubmit} layout="horizontal" hideRequiredMark>
<Form.Item {...is_language} label={formatMessage({ id: 'teamAdd.create.form.appName' })}>
{getFieldDecorator('group_id', {
initialValue: isService ? Number(groupId) : data.group_id || Number(group_id),
initialValue: initialGroupId,
rules: [{ required: true, message: formatMessage({ id: 'placeholder.select' }) }]
})(
<Select
Expand Down
Loading