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
20 changes: 14 additions & 6 deletions src/locales/en-US/resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,19 @@ const resource = {
'resourceCenter.tab.pod.emptyHint': 'If the list is empty, check whether workloads are created successfully and replicas are starting as expected.',

'resourceCenter.tab.network.title': 'Networking',
'resourceCenter.tab.network.navDescription': 'Manage Service type, ports, and selectors',
'resourceCenter.tab.network.navDescription': 'Manage Services, Ingresses, and traffic entry points',
'resourceCenter.tab.network.description': 'Manage traffic exposure in the team namespace and identify ports and entry points quickly.',
'resourceCenter.tab.network.listTitle': 'Network Resource List',
'resourceCenter.tab.network.listDescription': 'Review service type, port exposure, and selector bindings, and edit YAML directly.',
'resourceCenter.tab.network.listDescription': 'Review service type, port exposure, Ingress hosts, selector bindings, and edit YAML directly.',
'resourceCenter.tab.network.emptyTitle': 'No Network Resources Yet',
'resourceCenter.tab.network.emptyDescription': 'After creating a Service with YAML, you can review ClusterIP, ports, and selectors here.',
'resourceCenter.tab.network.emptyHint': 'If you need to expose traffic, create the workload first and then define the matching Service.',
'resourceCenter.tab.network.emptyDescription': 'After creating a Service or Ingress with YAML, ports, hosts, and selectors appear here.',
'resourceCenter.tab.network.emptyHint': 'If you need to expose traffic, create the workload first and then define the matching Service or Ingress.',
'resourceCenter.tab.network.services': 'Services',
'resourceCenter.tab.network.ingresses': 'Ingresses',
'resourceCenter.tab.network.ingressClass': 'IngressClass',
'resourceCenter.tab.network.hosts': 'Hosts',
'resourceCenter.tab.network.tlsHosts': 'TLS Hosts',
'resourceCenter.tab.network.backendServices': 'Backend Services',

'resourceCenter.tab.config.title': 'Configuration',
'resourceCenter.tab.config.navDescription': 'Unified view for ConfigMaps and Secrets',
Expand Down Expand Up @@ -180,11 +186,11 @@ const resource = {
'resourceCenter.metrics.pod.errorHelper': 'Pods that need logs or events checked',

'resourceCenter.metrics.network.total': 'Network Objects',
'resourceCenter.metrics.network.totalHelper': 'Service resources in the current team',
'resourceCenter.metrics.network.totalHelper': 'Service and Ingress resources in the current team',
'resourceCenter.metrics.network.ports': 'Exposed Ports',
'resourceCenter.metrics.network.portsHelper': 'Total declared ports and protocols',
'resourceCenter.metrics.network.exposed': 'Externally Exposed',
'resourceCenter.metrics.network.exposedHelper': 'Services that are not ClusterIP',
'resourceCenter.metrics.network.exposedHelper': 'Services that are not ClusterIP plus Ingress entry points',
'resourceCenter.metrics.network.selectorless': 'No Selector',
'resourceCenter.metrics.network.selectorlessHelper': 'Requires manual confirmation of traffic binding',

Expand Down Expand Up @@ -219,6 +225,7 @@ const resource = {
'resourceCenter.yaml.toolbar.createHint': 'Supports `.yaml` / `.yml`; you can continue reviewing and editing after import.',
'resourceCenter.yaml.toolbar.multiDoc': 'Multi-document supported',
'resourceCenter.yaml.toolbar.manualEdit': 'Manual editing preserved',
'resourceCenter.yaml.nativeResourceNotice': 'This creates Kubernetes native resources. After creation, view and manage them in K8S Native Resources; they will not appear in Application Management automatically. To create applications or components for Application Management, use the Application Management entry.',
'resourceCenter.yaml.placeholder': 'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: my-app\n...',
'resourceCenter.yaml.ok.create': 'Create',
'resourceCenter.yaml.ok.edit': 'Save',
Expand Down Expand Up @@ -305,6 +312,7 @@ const resource = {
'resourceCenter.helm.modal.tabExternalHelper': 'Supports official, self-hosted repos, and OCI',
'resourceCenter.helm.modal.tabUpload': 'Upload Chart Package',
'resourceCenter.helm.modal.tabUploadHelper': 'Upload a .tgz and install the release directly',
'resourceCenter.helm.modal.nativeResourceNotice': 'This installs a Helm release and manages it as Kubernetes native resources in K8S Native Resources. It will not appear in Application Management automatically. To create applications or components for Application Management, use the Application Management entry.',
'resourceCenter.helm.modal.externalNotice': 'Provide a chart address directly. Helm repo package URLs and OCI artifact addresses are both supported. Validation starts automatically when you go to the next step.',
'resourceCenter.helm.modal.externalNoticeShort': 'Provide a chart address directly. Helm repo package URLs and OCI artifact addresses are supported.',
'resourceCenter.helm.modal.externalSupport': 'Supports official Helm repos, self-hosted Helm repos, and OCI artifact sources.',
Expand Down
20 changes: 14 additions & 6 deletions src/locales/zh-CN/resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,19 @@ const resource = {
'resourceCenter.tab.pod.emptyHint': '如果这里为空,可以先检查工作负载是否创建完成或副本是否正常拉起。',

'resourceCenter.tab.network.title': '网络',
'resourceCenter.tab.network.navDescription': 'Service 类型、端口与选择器管理',
'resourceCenter.tab.network.navDescription': 'Service、Ingress 与流量入口管理',
'resourceCenter.tab.network.description': '管理团队命名空间下的网络暴露方式,快速识别端口与流量入口。',
'resourceCenter.tab.network.listTitle': '网络资源清单',
'resourceCenter.tab.network.listDescription': '查看 Service 类型、端口暴露、Selector 绑定关系,并支持直接编辑 YAML。',
'resourceCenter.tab.network.listDescription': '查看 Service 类型、端口暴露、Ingress 域名入口与 Selector 绑定关系,并支持直接编辑 YAML。',
'resourceCenter.tab.network.emptyTitle': '还没有网络资源',
'resourceCenter.tab.network.emptyDescription': '通过 YAML 新建 Service 后,可以在这里集中查看 ClusterIP、端口和选择器信息。',
'resourceCenter.tab.network.emptyHint': '如果要暴露服务,建议先创建工作负载,再补充对应的 Service 定义。',
'resourceCenter.tab.network.emptyDescription': '通过 YAML 新建 Service 或 Ingress 后,可以在这里集中查看端口、域名入口和选择器信息。',
'resourceCenter.tab.network.emptyHint': '如果要暴露服务,建议先创建工作负载,再补充对应的 Service 或 Ingress 定义。',
'resourceCenter.tab.network.services': 'Services',
'resourceCenter.tab.network.ingresses': 'Ingresses',
'resourceCenter.tab.network.ingressClass': 'IngressClass',
'resourceCenter.tab.network.hosts': 'Hosts',
'resourceCenter.tab.network.tlsHosts': 'TLS Hosts',
'resourceCenter.tab.network.backendServices': '后端服务',

'resourceCenter.tab.config.title': '配置',
'resourceCenter.tab.config.navDescription': 'ConfigMap 与 Secret 统一查看',
Expand Down Expand Up @@ -180,11 +186,11 @@ const resource = {
'resourceCenter.metrics.pod.errorHelper': '需要重点查看日志或事件',

'resourceCenter.metrics.network.total': '网络对象数',
'resourceCenter.metrics.network.totalHelper': '当前团队下的 Service 资源',
'resourceCenter.metrics.network.totalHelper': '当前团队下的 Service 与 Ingress 资源',
'resourceCenter.metrics.network.ports': '暴露端口',
'resourceCenter.metrics.network.portsHelper': '已声明的端口与协议总数',
'resourceCenter.metrics.network.exposed': '外部暴露',
'resourceCenter.metrics.network.exposedHelper': '非 ClusterIP 类型的 Service',
'resourceCenter.metrics.network.exposedHelper': '非 ClusterIP Service 与 Ingress 入口',
'resourceCenter.metrics.network.selectorless': '无选择器',
'resourceCenter.metrics.network.selectorlessHelper': '需要人工确认流量绑定对象',

Expand Down Expand Up @@ -219,6 +225,7 @@ const resource = {
'resourceCenter.yaml.toolbar.createHint': '支持 `.yaml` / `.yml`,导入后可继续校对与修改。',
'resourceCenter.yaml.toolbar.multiDoc': '支持多文档',
'resourceCenter.yaml.toolbar.manualEdit': '保留手动编辑',
'resourceCenter.yaml.nativeResourceNotice': '这里创建的是 Kubernetes 原生资源,创建后在「K8S 原生资源」中查看和管理,不会自动出现在「应用管理」。如需应用管理中的应用或组件,请从应用管理入口创建。',
'resourceCenter.yaml.placeholder': 'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: my-app\n...',
'resourceCenter.yaml.ok.create': '创建',
'resourceCenter.yaml.ok.edit': '保存',
Expand Down Expand Up @@ -305,6 +312,7 @@ const resource = {
'resourceCenter.helm.modal.tabExternalHelper': '支持官方、自建 Repo 与 OCI',
'resourceCenter.helm.modal.tabUpload': '上传 Chart 包',
'resourceCenter.helm.modal.tabUploadHelper': '上传 .tgz 后直接安装 Release',
'resourceCenter.helm.modal.nativeResourceNotice': '这里安装的是 Helm Release,会作为 Kubernetes 原生资源在「K8S 原生资源」中查看和管理,不会自动出现在「应用管理」。如需应用管理中的应用或组件,请从应用管理入口创建。',
'resourceCenter.helm.modal.externalNotice': '请直接填写 Chart 地址,支持 Helm 官方或自建 Helm Repo 中的 Chart 包地址,以及使用 OCI 格式的制品仓库。点击下一步后会自动检测并解析 Chart。',
'resourceCenter.helm.modal.externalNoticeShort': '请直接填写 Chart 地址,支持 Helm Repo 包地址和 OCI 制品地址。',
'resourceCenter.helm.modal.externalSupport': '支持 Helm 官方或自建 Helm Repo 仓库,以及使用 OCI 格式的制品仓库。',
Expand Down
8 changes: 8 additions & 0 deletions src/models/teamResources.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ export default {
const resources = [...configMaps, ...secrets];
yield put({ type: 'save', payload: { resources, total: resources.length } });
},
*fetchNetworkResources({ payload }, { call, put }) {
const servicesRes = yield call(listNsResources, { ...payload, group: '', version: 'v1', resource: 'services' });
const ingressesRes = yield call(listNsResources, { ...payload, group: 'networking.k8s.io', version: 'v1', resource: 'ingresses' });
const services = (servicesRes && servicesRes.bean && servicesRes.bean.list) || [];
const ingresses = (ingressesRes && ingressesRes.bean && ingressesRes.bean.list) || [];
const resources = [...services, ...ingresses];
yield put({ type: 'save', payload: { resources, total: resources.length } });
},
*createResource({ payload, callback, handleError }, { call }) {
const res = yield call(createNsResource, { ...payload, handleError });
if (res && callback) callback(res);
Expand Down
77 changes: 63 additions & 14 deletions src/pages/Extension/pluginCapacity/pluginTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,59 @@ class Index extends PureComponent {
loading: false
})
} else {
this.setState({
pluginList: [],
loading: false
})
this.handleInstalledPluginList(eid);
}
},
handleError: () => {
this.handleInstalledPluginList(eid);
}
})
}

normalizeInstalledPlugin = plugin => ({
...plugin,
plugin_id: plugin.plugin_id || plugin.name,
plugin_name: plugin.plugin_name || plugin.alias || plugin.display_name || plugin.name,
description: plugin.description || '',
installed: true,
installed_version: plugin.installed_version || plugin.version || '',
can_upgrade: false,
upgradeable: false,
latest_version: plugin.latest_version || '',
author: plugin.author || 'Rainbond 官方',
app_level: plugin.app_level || plugin.appLevel || 'enterprise'
})

handleInstalledPluginList = (eid, callback) => {
const { dispatch, regionName } = this.props;
dispatch({
type: 'teamControl/fetchPluginUrl',
payload: {
enterprise_id: eid,
region_name: regionName,
},
callback: res => {
const plugins = res && res.list && res.list.length > 0
? res.list.map(item => this.normalizeInstalledPlugin(item))
: [];
this.setState({
pluginList: plugins,
loading: false
});
if (callback) {
callback(plugins);
}
},
handleError: () => {
this.setState({
pluginList: [],
loading: false
})
});
if (callback) {
callback([]);
}
}
})
});
}

onJumpApp = (value, tab = 'upgrade') => {
Expand Down Expand Up @@ -454,6 +494,18 @@ class Index extends PureComponent {
});
}

completeInstallIfRunning = (pluginId, plugins) => {
const target = plugins.find(p => p.plugin_id === pluginId);
const status = target && `${target.status || ''}`.toUpperCase();
if (target && status === 'RUNNING') {
this.stopInstallPolling();
this.setState(prev => ({
installingPlugins: { ...prev.installingPlugins, [pluginId]: false },
installModalPhase: 'RUNNING',
}));
}
}

startInstallPolling = (pluginId) => {
this.stopInstallPolling();
this.installPollTimer = setInterval(() => {
Expand All @@ -470,14 +522,11 @@ class Index extends PureComponent {
callback: res => {
if (res && res.list && res.list.length > 0) {
this.setState({ pluginList: res.list });
const target = res.list.find(p => p.plugin_id === pluginId);
if (target && target.status === 'RUNNING') {
this.stopInstallPolling();
this.setState(prev => ({
installingPlugins: { ...prev.installingPlugins, [pluginId]: false },
installModalPhase: 'RUNNING',
}));
}
this.completeInstallIfRunning(pluginId, res.list);
} else {
this.handleInstalledPluginList(eid, plugins => {
this.completeInstallIfRunning(pluginId, plugins);
});
}
},
});
Expand Down
12 changes: 6 additions & 6 deletions src/pages/Group/components/AppShareAppInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class AppShareAppInfo extends PureComponent {
const { getFieldDecorator, getFieldValue } = form;
const pd16 = { padding: 16 };
if (app.extend_method_map) {
const steps = getFieldValue(`${ID}||step_node`);
const steps = getFieldValue(`extend||step_node||${ID}`);
return (
<div className={styles.componentSection}>
<div className={styles.componentSectionHeader}>
Expand All @@ -152,7 +152,7 @@ class AppShareAppInfo extends PureComponent {
})}
style={pd16}
>
{getFieldDecorator(`${ID}||min_node`, {
{getFieldDecorator(`extend||min_node||${ID}`, {
initialValue: app.extend_method_map.min_node,
rules: [
{
Expand Down Expand Up @@ -181,7 +181,7 @@ class AppShareAppInfo extends PureComponent {
})}
style={pd16}
>
{getFieldDecorator(`${ID}||max_node`, {
{getFieldDecorator(`extend||max_node||${ID}`, {
initialValue: app.extend_method_map.max_node,
rules: [
{
Expand Down Expand Up @@ -210,7 +210,7 @@ class AppShareAppInfo extends PureComponent {
})}
style={pd16}
>
{getFieldDecorator(`${ID}||step_node`, {
{getFieldDecorator(`extend||step_node||${ID}`, {
initialValue: app.extend_method_map.step_node,
rules: [
{
Expand Down Expand Up @@ -239,7 +239,7 @@ class AppShareAppInfo extends PureComponent {
})}
style={pd16}
>
{getFieldDecorator(`${ID}||init_memory`, {
{getFieldDecorator(`extend||init_memory||${ID}`, {
initialValue: app.extend_method_map.init_memory || 0,
rules: [
{
Expand Down Expand Up @@ -272,7 +272,7 @@ class AppShareAppInfo extends PureComponent {
})}
style={pd16}
>
{getFieldDecorator(`${ID}||container_cpu`, {
{getFieldDecorator(`extend||container_cpu||${ID}`, {
initialValue: app.extend_method_map.container_cpu || 0,
rules: [
{
Expand Down
108 changes: 108 additions & 0 deletions src/pages/Group/components/appShareFormHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
const cloneShareService = item => ({
...item,
extend_method_map: item.extend_method_map
? { ...item.extend_method_map }
: item.extend_method_map,
dep_service_map_list: Array.isArray(item.dep_service_map_list)
? item.dep_service_map_list.map(dep => ({ ...dep }))
: [],
service_connect_info_map_list: Array.isArray(item.service_connect_info_map_list)
? item.service_connect_info_map_list.map(config => ({ ...config }))
: [],
service_env_map_list: Array.isArray(item.service_env_map_list)
? item.service_env_map_list.map(config => ({ ...config }))
: []
});

const collectShareServiceData = ({
shareServiceList = [],
selectedShareKeys = [],
componentRefs = []
}) => {
const shareServiceData = shareServiceList.map(cloneShareService);
let componentFormHasError = false;

componentRefs.forEach(app => {
if (!app || !app.props || !app.props.form) {
return;
}
const apptab = app.props.tab;
let componentValues = null;
app.props.form.validateFields((errs, val) => {
if (errs) {
componentFormHasError = true;
return;
}
componentValues = val;
});
if (componentFormHasError || !componentValues) {
return;
}
shareServiceData.forEach(option => {
const ID = option.service_id;
if (option.service_alias !== apptab) {
return;
}
Object.keys(componentValues).forEach(index => {
const indexarr = index.split('||');
const firstInfo = indexarr && indexarr.length > 0 && indexarr[0];
if (!firstInfo) {
return;
}
const isConnect = firstInfo === 'connect';
const isEnv = firstInfo === 'env';

if (isConnect && indexarr[2] !== 'random') {
option.service_connect_info_map_list.forEach(serapp => {
if (
serapp.attr_name === indexarr[1] &&
String(ID) === String(indexarr[3])
) {
serapp[indexarr[2]] = componentValues[index];
serapp.is_change = true;
}
});
}

if (isEnv) {
option.service_env_map_list.forEach(serapp => {
if (
serapp.attr_name === indexarr[1] &&
String(ID) === String(indexarr[2])
) {
serapp.attr_value = componentValues[index];
serapp.is_change = true;
}
});
}

if (
firstInfo === 'extend' &&
option.extend_method_map &&
String(ID) === String(indexarr[2])
) {
option.extend_method_map[indexarr[1]] = componentValues[index];
}
});
});
});

const selectedShareServices = [];
selectedShareKeys.forEach(shareKey => {
shareServiceData.forEach(option => {
if (shareKey === option.service_share_uuid) {
selectedShareServices.push(option);
}
});
});

return {
componentFormHasError,
shareServiceData,
selectedShareServices
};
};

module.exports = {
collectShareServiceData
};
Loading
Loading