diff --git a/.claude/specs/app-version-delete-history.md b/.claude/specs/app-version-delete-history.md new file mode 100644 index 000000000..0f05465cf --- /dev/null +++ b/.claude/specs/app-version-delete-history.md @@ -0,0 +1,15 @@ +# App Version Delete History Spec + +- Design doc: `/Users/zhangqihang/MyWork/workrc/rainbond-ui/docs/plans/2026-03-24-app-version-delete-design.md` +- Scope: `rainbond-console`, `rainbond-ui` +- Goal: let workspace app version timelines delete historical snapshots while preventing current snapshot deletion. + +Execution order: + +1. `rainbond-console` +2. `rainbond-ui` + +Verification gates: + +- `rainbond-console`: `python -m py_compile console/views/app_version.py console/services/app_version_service.py`, `make check` +- `rainbond-ui`: `yarn build` diff --git a/.claude/specs/app-version-delete-history.yaml b/.claude/specs/app-version-delete-history.yaml new file mode 100644 index 000000000..79589106f --- /dev/null +++ b/.claude/specs/app-version-delete-history.yaml @@ -0,0 +1,103 @@ +meta: + name: "app-version-delete-history" + version: "1.0" + repo: "/Users/zhangqihang/MyWork/workrc" + branch: "v6.7.0-release-dev" + design_doc: "/Users/zhangqihang/MyWork/workrc/rainbond-ui/docs/plans/2026-03-24-app-version-delete-design.md" + +sprints: + - id: sprint-1 + name: "Console Snapshot Delete API" + commits: + - id: commit-1 + message: "feat: add app snapshot delete api" + tasks: [task-1.1, task-1.2] + tasks: + - id: task-1.1 + name: "Add snapshot delete service rule" + status: pending + files: + modify: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-console/console/services/app_version_service.py" + lines: "250-262,431-460" + steps: + - action: "implement" + description: "Add a delete_snapshot method that loads the hidden template, rejects deleting the latest snapshot, and removes only historical snapshot records." + run: "python -m py_compile console/services/app_version_service.py" + expect: "PASS" + acceptance: + - cmd: "python -m py_compile console/services/app_version_service.py" + expect: "PASS" + references: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-console/console/services/app_version_service.py:250-262" + note: "Current snapshot list ordering defines which version is current" + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-console/console/services/app_version_service.py:431-460" + note: "Current snapshot lookup and rollback validation" + - id: task-1.2 + name: "Expose delete endpoint on snapshot detail route" + status: pending + files: + modify: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-console/console/views/app_version.py" + lines: "41-46" + steps: + - action: "implement" + description: "Add DELETE handling for app snapshot detail requests and return a success message after the service deletes a historical snapshot." + run: "python -m py_compile console/views/app_version.py" + expect: "PASS" + acceptance: + - cmd: "python -m py_compile console/views/app_version.py" + expect: "PASS" + - cmd: "make check" + expect: "PASS" + references: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-console/console/views/app_version.py:41-46" + note: "Existing snapshot detail endpoint to extend with DELETE" + + - id: sprint-2 + name: "UI Historical Snapshot Delete Flow" + commits: + - id: commit-2 + message: "feat: support deleting historical app snapshots" + tasks: [task-2.1, task-2.2] + tasks: + - id: task-2.1 + name: "Add app snapshot delete service helper" + status: pending + files: + modify: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-ui/src/services/api.js" + lines: "523-574" + steps: + - action: "implement" + description: "Add a deleteAppVersionSnapshot request helper for the new console DELETE endpoint." + run: "yarn build" + expect: "PASS" + acceptance: + - cmd: "yarn build" + expect: "PASS" + references: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-ui/src/services/api.js:523-574" + note: "Existing app version overview, list, detail and rollback helpers" + - id: task-2.2 + name: "Show delete action on history-only timeline nodes" + status: pending + files: + modify: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-ui/src/pages/AppVersion/index.js" + lines: "331-350,561-584,936-1065" + steps: + - action: "implement" + description: "Add a delete confirmation flow, show delete only on non-latest snapshot items, and refresh overview plus snapshot timeline after successful deletion." + run: "yarn build" + expect: "PASS" + acceptance: + - cmd: "yarn build" + expect: "PASS" + references: + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-ui/src/pages/AppVersion/index.js:331-350" + note: "Existing snapshot fetch and refresh entrypoint" + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-ui/src/pages/AppVersion/index.js:561-584" + note: "Existing action callback style for snapshot publish flow" + - path: "/Users/zhangqihang/MyWork/workrc/rainbond-ui/src/pages/AppVersion/index.js:936-1065" + note: "Current timeline action rendering area" diff --git a/.claude/specs/team-plugin-tab-integration.md b/.claude/specs/team-plugin-tab-integration.md new file mode 100644 index 000000000..37eb632b0 --- /dev/null +++ b/.claude/specs/team-plugin-tab-integration.md @@ -0,0 +1,16 @@ +# Team Plugin Tab Integration Spec + +- Design doc: `/Users/guox/Desktop/Project/6.28/rainbond-ui/docs/plans/2026-03-25-team-plugin-tab-integration-design.md` +- Scope: `rainbond-ui` +- Goal: move the plugin home list into the Team settings tabs, retire the standalone `/myplugns` home route, and keep plugin detail plus create/install routes independent. + +Execution order: + +1. Extract reusable plugin home content +2. Integrate Team page plugin tab and query routing +3. Redirect legacy `/myplugns` home route +4. Unify create and install success navigation + +Verification gates: + +- `rainbond-ui`: `yarn build` diff --git a/.claude/specs/team-plugin-tab-integration.yaml b/.claude/specs/team-plugin-tab-integration.yaml new file mode 100644 index 000000000..79fa877b1 --- /dev/null +++ b/.claude/specs/team-plugin-tab-integration.yaml @@ -0,0 +1,133 @@ +meta: + name: "team-plugin-tab-integration" + version: "1.0" + repo: "/Users/guox/Desktop/Project/6.28/rainbond-ui" + branch: "v6.7.0-release-dev" + design_doc: "/Users/guox/Desktop/Project/6.28/rainbond-ui/docs/plans/2026-03-25-team-plugin-tab-integration-design.md" + +sprints: + - id: sprint-1 + name: "Extract Reusable Plugin Home Content" + commits: + - id: commit-1 + message: "refactor: extract reusable plugin home content" + tasks: [task-1.1, task-1.2] + tasks: + - id: task-1.1 + name: "Move plugin home list logic into a reusable content component" + status: pending + files: + create: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/components/PluginListContent.js" + modify: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/index.js" + lines: "181-647" + steps: + - action: "implement" + description: "Extract the plugin home card list, default plugin install flow, delete flow, and create/install navigation into a reusable component that does not render its own PageHeaderLayout." + run: "yarn build" + expect: "PASS" + acceptance: + - cmd: "yarn build" + expect: "PASS" + references: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/index.js:181-647" + note: "Current plugin home list implementation to be extracted" + - id: task-1.2 + name: "Keep plugin detail route shell and embedded home usage compatible" + status: pending + files: + modify: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/index.js" + lines: "651-683" + steps: + - action: "implement" + description: "Update the Plugin route shell so the extracted home content can still be reused where needed, while pluginId-based Manage rendering remains unchanged." + run: "yarn build" + expect: "PASS" + acceptance: + - cmd: "yarn build" + expect: "PASS" + references: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/index.js:651-683" + note: "Current route split between plugin home and detail pages" + + - id: sprint-2 + name: "Integrate Team Plugin Tab And Retire Legacy Home Route" + commits: + - id: commit-2 + message: "feat: show plugin home in team settings tab" + tasks: [task-2.1, task-2.2, task-2.3] + tasks: + - id: task-2.1 + name: "Add plugin tab to Team settings page with query-driven activation" + status: pending + files: + modify: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Team/index.js" + lines: "1-414" + steps: + - action: "implement" + description: "Parse location.search for tab, add a plugin tab gated by team_plugin_manage permission, and render the extracted plugin home content when scope equals plugin." + run: "yarn build" + expect: "PASS" + acceptance: + - cmd: "yarn build" + expect: "PASS" + references: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Team/index.js:27-80" + note: "Current scope initialization logic" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Team/index.js:332-414" + note: "Current Team tab list and tab body rendering" + - id: task-2.2 + name: "Redirect legacy /myplugns home route to the Team plugin tab" + status: pending + files: + modify: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/index.js" + lines: "651-683" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/config/router.config.js" + lines: "568-603" + steps: + - action: "implement" + description: "Keep /myplugns/:pluginId for detail pages, but redirect /myplugns to /team/:teamName/region/:regionName/team?tab=plugin so old links and menu entries still land on the new integrated home." + run: "yarn build" + expect: "PASS" + acceptance: + - cmd: "yarn build" + expect: "PASS" + references: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/config/router.config.js:568-603" + note: "Legacy plugin route definitions" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/index.js:669-683" + note: "Current pluginId-based render split" + - id: task-2.3 + name: "Unify create and market-install success return paths" + status: pending + files: + modify: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/Create.js" + lines: "16-36" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Create/market_plugin.js" + lines: "495-725,1304-1477" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/locales/zh-CN/team.js" + lines: "503-579" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/locales/en-US/team.js" + lines: "493-573" + steps: + - action: "implement" + description: "Replace success redirects that still return to /myplugns with /team/:teamName/region/:regionName/team?tab=plugin, and add any missing Team tab locale text for the new plugin entry." + run: "yarn build" + expect: "PASS" + acceptance: + - cmd: "yarn build" + expect: "PASS" + references: + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Plugin/Create.js:16-36" + note: "Create plugin success redirect" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Create/market_plugin.js:509-539" + note: "Market install modal success redirect" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Create/market_plugin.js:610-636" + note: "Local market create success redirect" + - path: "/Users/guox/Desktop/Project/6.28/rainbond-ui/src/pages/Create/market_plugin.js:696-724" + note: "Cloud market create success redirect" diff --git a/config/config.js b/config/config.js index 92b9b92a3..8fbdf3804 100644 --- a/config/config.js +++ b/config/config.js @@ -7,6 +7,7 @@ if (process.env.SEPARATION === 'true') { publcPath = `/`; } const isHistory = process.env.ROUTE_MODE === 'history'; +const proxyTarget = process.env.CONSOLE_PROXY_TARGET || 'http://127.0.0.1:7070'; export default { history: { type: isHistory ? 'browser' : 'hash' }, @@ -35,24 +36,24 @@ export default { routes: routerConfig, proxy: { '/console': { - target: 'http://127.0.0.1:7070', + target: proxyTarget, changeOrigin: true }, '/data': { - target: 'http://127.0.0.1:7070', + target: proxyTarget, changeOrigin: true }, '/openapi/v1': { - target: 'http://127.0.0.1:7070', + target: proxyTarget, changeOrigin: true }, '/enterprise-server': { - target: 'http://127.0.0.1:7070', + target: proxyTarget, changeOrigin: true }, '/app-server': { - target: 'http://127.0.0.1:7070', + target: proxyTarget, changeOrigin: true }, } -}; \ No newline at end of file +}; diff --git a/config/router.config.js b/config/router.config.js index e0751d146..234af5c87 100644 --- a/config/router.config.js +++ b/config/router.config.js @@ -161,6 +161,12 @@ export default [ name: 'LogManagement', authority: ['admin', 'user'] }, + { + path: '/enterprise/:eid/region/:regionName/platform-resources', + component: './PlatformResources', + name: 'PlatformResources', + authority: ['admin', 'user'] + }, { path: '/enterprise/:eid/extension', component: './Extension', @@ -340,6 +346,41 @@ export default [ authority: ['admin', 'user'], title: '流水线' }, + { + path: '/team/:teamName/region/:regionName/k8s-center/workloads/:resource/:name', + component: './ResourceCenter/WorkloadDetail', + name: 'ResourceCenterWorkloadDetail', + authority: ['admin', 'user'], + title: '工作负载详情' + }, + { + path: '/team/:teamName/region/:regionName/k8s-center/pods/:podName', + component: './ResourceCenter/PodDetail', + name: 'ResourceCenterPodDetail', + authority: ['admin', 'user'], + title: '容器组详情' + }, + { + path: '/team/:teamName/region/:regionName/k8s-center/services/:serviceName', + component: './ResourceCenter/ServiceDetail', + name: 'ResourceCenterServiceDetail', + authority: ['admin', 'user'], + title: '服务详情' + }, + { + path: '/team/:teamName/region/:regionName/k8s-center/helm/:releaseName', + component: './ResourceCenter/HelmDetail', + name: 'ResourceCenterHelmDetail', + authority: ['admin', 'user'], + title: 'Helm 应用详情' + }, + { + path: '/team/:teamName/region/:regionName/k8s-center', + component: './ResourceCenter', + name: 'ResourceCenter', + authority: ['admin', 'user'], + title: 'K8S 原生资源' + }, { path: '/team/:teamName/region/:regionName/apps/:appID/upgrade', component: './Upgrade', @@ -347,6 +388,13 @@ export default [ authority: ['admin', 'user'], title: '云市应用升级' }, + { + path: '/team/:teamName/region/:regionName/apps/:appID/version', + component: './AppVersion', + name: 'AppVersion', + authority: ['admin', 'user'], + title: '应用版本' + }, { path: '/team/:teamName/region/:regionName/apps/:appID/plugins/:pluginId', component: './RbdPlugins', diff --git a/src/common/appMenu.js b/src/common/appMenu.js index dc2a24406..a2bde466c 100644 --- a/src/common/appMenu.js +++ b/src/common/appMenu.js @@ -49,14 +49,12 @@ function menuData(teamName, regionName, appID, permissionsInfo, pluginList, curr // ============ 第二组:管理功能 ============ const adminItems = []; - if (isAppRelease) { - adminItems.push({ - name: formatMessage({ id: 'menu.app.publish' }), - icon: getMenuSvg.getSvg('publish'), - path: `team/${teamName}/region/${regionName}/apps/${appID}/publish`, - authority: ['admin', 'user'] - }); - } + adminItems.push({ + name: formatMessage({ id: 'menu.app.version' }), + icon: getMenuSvg.getSvg('version'), + path: `team/${teamName}/region/${regionName}/apps/${appID}/version`, + authority: ['admin', 'user'] + }); if (isAppGatewayMonitor || isAppRouteManage || isAppTargetServices || isAppCertificate) { adminItems.push({ @@ -67,15 +65,6 @@ function menuData(teamName, regionName, appID, permissionsInfo, pluginList, curr }); } - if (isAppUpgrade) { - adminItems.push({ - name: formatMessage({ id: 'menu.app.upgrade' }), - icon: getMenuSvg.getSvg('upgrade'), - path: `team/${teamName}/region/${regionName}/apps/${appID}/upgrade`, - authority: ['admin', 'user'] - }); - } - if (PluginUtil.isInstallEnterprisePlugin(pluginList) && (currentUser.is_enterprise_admin || !rainbondInfo?.security_restrictions?.enable)) { adminItems.push({ name: formatMessage({ id: 'menu.app.backup' }), diff --git a/src/common/enterpriseMenu.js b/src/common/enterpriseMenu.js index d327a94b3..4e7457ec5 100644 --- a/src/common/enterpriseMenu.js +++ b/src/common/enterpriseMenu.js @@ -67,6 +67,17 @@ function menuData(eid, currentUser, enterprise, pluginList, clusterList) { } ]; + // 平台资源(需要至少一个集群) + if (clusterList && clusterList.length > 0) { + const firstCluster = clusterList[0]; + resourceItems.push({ + name: formatMessage({ id: 'menu.enterprise.platform_resources', defaultMessage: '平台资源' }), + icon: getMenuSvg.getSvg('StorageMgtL'), + path: `/enterprise/${eid}/region/${firstCluster.region_name}/platform-resources`, + authority: ['admin', 'user'] + }); + } + // 计量计费 const billPlugin = PluginUtil.getPluginInfo(pluginList, 'rainbond-bill'); if (billPlugin && Object.keys(billPlugin).length !== 0) { diff --git a/src/common/getMenuSvg.js b/src/common/getMenuSvg.js index ea2062b18..5fc261e0d 100644 --- a/src/common/getMenuSvg.js +++ b/src/common/getMenuSvg.js @@ -2,44 +2,49 @@ const getMenuSvg = { getSvg(type, size) { const svg = { // 企业侧边栏图标 + StorageMgtL: ( + + + + ), dashboard: ( - + ), shareAlt: ( - + ), teams: ( - + ), clusters: ( - + ), users: ( - + ), logs: ( - + ), extension: ( - + ), setting: ( - + ), // 团队侧边栏图标 @@ -83,6 +88,14 @@ const getMenuSvg = { ), + k8s: ( + + + + + + + ), Pipeline: ( @@ -105,7 +118,7 @@ const getMenuSvg = { ), gateway: ( - + ), api: ( @@ -123,9 +136,17 @@ const getMenuSvg = { ), + version: ( + + + + + + + ), kubenetes: ( - + ), gray: ( @@ -135,7 +156,7 @@ const getMenuSvg = { ), backup: ( - + ), spring: ( @@ -145,7 +166,7 @@ const getMenuSvg = { ), plugin: ( - + ), bill: ( @@ -172,9 +193,14 @@ const getMenuSvg = { + ), + resource: ( + + + ) } return svg[type] || type; } } -export default getMenuSvg; \ No newline at end of file +export default getMenuSvg; diff --git a/src/common/teamMenu.js b/src/common/teamMenu.js index 0bac8aa68..9054cd73d 100644 --- a/src/common/teamMenu.js +++ b/src/common/teamMenu.js @@ -22,9 +22,10 @@ function setTeamMenu(pluginMenu, menuName) { * @param {string} regionName - 集群名称 * @param {object} permissionsInfo - 权限信息 * @param {array} pluginList - 插件列表 + * @param {object} enterpriseSettings - 企业平台设置(可选) * @returns {array} 分组菜单数组 */ -function menuData(teamName, regionName, permissionsInfo, pluginList) { +function menuData(teamName, regionName, permissionsInfo, pluginList, enterpriseSettings) { const menuGroups = []; function results() { @@ -36,24 +37,37 @@ function menuData(teamName, regionName, permissionsInfo, pluginList) { const pluginArr = PluginUtil.segregatePluginsByHierarchy(pluginList, 'Team'); - // ============ 第一组:团队总览(无标题) ============ + // ============ 第一组:工作空间主入口(无标题) ============ + const overviewItems = [ + { + name: formatMessage({ id: 'menu.team.dashboard' }), + icon: getMenuSvg.getSvg('dashboard'), + path: `team/${teamName}/region/${regionName}/index`, + authority: ['admin', 'user'] + } + ]; + console.log(enterpriseSettings, 'enterpriseSettings'); + + if (enterpriseSettings && enterpriseSettings.enable_team_resource_view) { + console.log(1111); + + overviewItems.push({ + name: formatMessage({ id: 'menu.team.resource_center', defaultMessage: 'K8S Native Resources' }), + icon: getMenuSvg.getSvg('k8s'), + path: `team/${teamName}/region/${regionName}/k8s-center`, + authority: ['admin', 'user'] + }); + } + menuGroups.push({ groupKey: 'overview', groupName: '', // 无标题 - items: [ - { - name: formatMessage({ id: 'menu.team.dashboard' }), - icon: getMenuSvg.getSvg('dashboard'), - path: `team/${teamName}/region/${regionName}/index`, - authority: ['admin', 'user'] - } - ] + items: overviewItems }); // ============ 第二组:管理功能 ============ if (permissionsInfo) { const { - isTeamPluginManage, isTeamDynamic, isTeamRegion, isTeamRole, @@ -72,16 +86,6 @@ function menuData(teamName, regionName, permissionsInfo, pluginList) { }); } - // 插件管理 - if (isTeamPluginManage) { - adminItems.push({ - name: formatMessage({ id: 'menu.team.plugin' }), - icon: getMenuSvg.getSvg('api'), - path: `team/${teamName}/region/${regionName}/myplugns`, - authority: ['admin', 'user'] - }); - } - // 团队设置 if (isTeamDynamic || isTeamRegion || isTeamRole || isTeamRegistryAuth) { adminItems.push({ @@ -158,15 +162,15 @@ function formatter(menuGroups) { /** * 获取分组菜单数据 */ -export const getMenuData = (teamName, regionName, permissionsInfo, pluginList) => { - const menuGroups = menuData(teamName, regionName, permissionsInfo, pluginList); +export const getMenuData = (teamName, regionName, permissionsInfo, pluginList, enterpriseSettings) => { + const menuGroups = menuData(teamName, regionName, permissionsInfo, pluginList, enterpriseSettings); return formatter(menuGroups); }; /** * 将分组菜单展平为普通菜单数组(兼容旧代码) */ -export const getFlatMenuData = (teamName, regionName, permissionsInfo, pluginList) => { - const menuGroups = getMenuData(teamName, regionName, permissionsInfo, pluginList); +export const getFlatMenuData = (teamName, regionName, permissionsInfo, pluginList, enterpriseSettings) => { + const menuGroups = getMenuData(teamName, regionName, permissionsInfo, pluginList, enterpriseSettings); return menuGroups.reduce((acc, group) => [...acc, ...group.items], []); }; diff --git a/src/components/AppCreateConfigFile/index.js b/src/components/AppCreateConfigFile/index.js index 00cbaa060..219a09b9c 100644 --- a/src/components/AppCreateConfigFile/index.js +++ b/src/components/AppCreateConfigFile/index.js @@ -24,11 +24,20 @@ import cookie from '@/utils/cookie'; import CodeBuildConfig from '../CodeBuildConfig'; import PriceCard from '../../components/PriceCard'; import handleAPIError from '../../utils/error'; +const { mergeCreateRuntimeInfo } = require('../CodeBuildConfig/buildEnvHelpers'); import styles from './setting.less'; const RadioButton = Radio.Button; const RadioGroup = Radio.Group; const { Option } = Select; +const SOURCE_BUILD_CONFIG_KEY = 'source_build_config'; +const readSourceBuildConfig = () => { + if (typeof window === 'undefined' || !window.sessionStorage) { + return null; + } + const config = window.sessionStorage.getItem(SOURCE_BUILD_CONFIG_KEY); + return config ? JSON.parse(config) : null; +}; @connect(null, null, null, { withRef: true }) @Form.create() // 基础信息设置 @@ -1126,7 +1135,10 @@ class RenderDeploy extends PureComponent { }, callback: data => { if (data) { - this.setState({ runtimeInfo: data.bean ? data.bean : {} }); + const runtimeInfo = data.bean ? data.bean : {}; + this.setState({ + runtimeInfo: mergeCreateRuntimeInfo(runtimeInfo, readSourceBuildConfig()) + }); } }, handleError: err => { diff --git a/src/components/AppCreateConfigFile/index.node.test.js b/src/components/AppCreateConfigFile/index.node.test.js new file mode 100644 index 000000000..963a6a1cf --- /dev/null +++ b/src/components/AppCreateConfigFile/index.node.test.js @@ -0,0 +1,19 @@ +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +const source = fs.readFileSync(path.join(__dirname, 'index.js'), 'utf8'); + +assert.match( + source, + /const \{ mergeCreateRuntimeInfo \} = require\('\.\.\/CodeBuildConfig\/buildEnvHelpers'\);/, + 'AppCreateConfigFile should import mergeCreateRuntimeInfo for create-flow runtime hydration' +); + +assert.match( + source, + /runtimeInfo:\s*mergeCreateRuntimeInfo\(runtimeInfo,\s*readSourceBuildConfig\(\)\)/, + 'AppCreateConfigFile should prefer the latest source-build detection when initializing runtimeInfo' +); + +console.log('app create config file runtime merge test passed'); diff --git a/src/components/AppCreateMoreService/index.js b/src/components/AppCreateMoreService/index.js index 6b4558be2..f9f517080 100644 --- a/src/components/AppCreateMoreService/index.js +++ b/src/components/AppCreateMoreService/index.js @@ -124,14 +124,21 @@ class BaseInfo extends PureComponent { if (item.id == editData.id) { item.cname = fieldsValue.cname; item.arch = fieldsValue.arch; + const procfileValue = (fieldsValue.PROCFILE || '').trim(); + let hasProcfile = false; item.envs.map(item => { item.name == "BUILD_MAVEN_CUSTOM_OPTS" ? (item.value = fieldsValue.BUILD_MAVEN_CUSTOM_OPTS) : ""; - item.name == "BUILD_PROCFILE" - ? (item.value = fieldsValue.PROCFILE) - : ""; + if (item.name == "BUILD_PROCFILE") { + hasProcfile = true; + item.value = procfileValue; + } }); + if (!hasProcfile && procfileValue) { + item.envs.push({ name: "BUILD_PROCFILE", value: procfileValue }); + } + item.envs = item.envs.filter(env => !(env.name == "BUILD_PROCFILE" && !env.value)); } }); this.setState( @@ -345,12 +352,6 @@ class BaseInfo extends PureComponent { {getFieldDecorator("PROCFILE", { initialValue: startValue && startValue, - rules: [ - { - required: true, - message: formatMessage({id:'JavaMaven.start_input'}) - } - ] })(