feat: support subnet detail page
1. Support subnet detail page: base info tab && ports tab 2. Refactor subnet codes: adjust a more reasonable directory structure 3. Update port related code to support ports list in the subnet detail page 4. Update port detail back to the list page: entering from the instance/network/subnet detail page will return to the instance/network/subnet detail page 5. In the instance detail interface tab, remove the device owner filter Change-Id: I02edd0cb54a76f6b590411be5f93b57bb89c6cd6
This commit is contained in:
parent
0775c02b67
commit
dfde82e667
@ -293,6 +293,13 @@ const renderMenu = (t) => {
|
|||||||
level: 2,
|
level: 2,
|
||||||
routePath: '/network/networks-admin/detail/:id',
|
routePath: '/network/networks-admin/detail/:id',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/networks-admin\/detail\/.[^/]+\/subnet\/.[^/]+$/,
|
||||||
|
name: t('Subnet Detail'),
|
||||||
|
key: 'subnetDetailAdmin',
|
||||||
|
level: 2,
|
||||||
|
routePath: '/network/networks-admin/detail/:networkId/subnet/:id',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -308,6 +315,28 @@ const renderMenu = (t) => {
|
|||||||
level: 2,
|
level: 2,
|
||||||
routePath: '/network/port-admin/detail/:id',
|
routePath: '/network/port-admin/detail/:id',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/networks-admin\/detail\/.[^/]+\/port\/.[^/]+$/,
|
||||||
|
name: t('Port Detail'),
|
||||||
|
key: 'networkPortDetailAdmin',
|
||||||
|
level: 2,
|
||||||
|
routePath: '/network/networks-admin/detail/:networkId/port/:id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/networks-admin\/detail\/.[^/]+\/subnet\/.[^/]+\/port\/.[^/]+$/,
|
||||||
|
name: t('Port Detail'),
|
||||||
|
key: 'subnetPortDetailAdmin',
|
||||||
|
level: 2,
|
||||||
|
routePath:
|
||||||
|
'/network/networks-admin/detail/:networkId/subnet/:subnetId/port/:id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/instance-admin\/detail\/.[^/]+\/port\/.[^/]+$/,
|
||||||
|
name: t('Port Detail'),
|
||||||
|
key: 'instancePortDetailAdmin',
|
||||||
|
level: 2,
|
||||||
|
routePath: '/network/instance-admin/detail/:instanceId/port/:id',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -259,6 +259,13 @@ const renderMenu = (t) => {
|
|||||||
level: 2,
|
level: 2,
|
||||||
routePath: '/network/networks/detail/:id',
|
routePath: '/network/networks/detail/:id',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/networks\/detail\/.[^/]+\/subnet\/.[^/]+$/,
|
||||||
|
name: t('Subnet Detail'),
|
||||||
|
key: 'subnetDetail',
|
||||||
|
level: 2,
|
||||||
|
routePath: '/network/networks/detail/:networkId/subnet/:id',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -274,6 +281,28 @@ const renderMenu = (t) => {
|
|||||||
level: 2,
|
level: 2,
|
||||||
routePath: '/network/port/detail/:id',
|
routePath: '/network/port/detail/:id',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/networks\/detail\/.[^/]+\/port\/.[^/]+$/,
|
||||||
|
name: t('Port Detail'),
|
||||||
|
key: 'networkPortDetail',
|
||||||
|
level: 2,
|
||||||
|
routePath: '/network/networks/detail/:networkId/port/:id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/networks\/detail\/.[^/]+\/subnet\/.[^/]+\/port\/.[^/]+$/,
|
||||||
|
name: t('Port Detail'),
|
||||||
|
key: 'subnetPortDetail',
|
||||||
|
level: 2,
|
||||||
|
routePath:
|
||||||
|
'/network/networks/detail/:networkId/subnet/:subnetId/port/:id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: /^\/network\/instance\/detail\/.[^/]+\/port\/.[^/]+$/,
|
||||||
|
name: t('Port Detail'),
|
||||||
|
key: 'instancePortDetail',
|
||||||
|
level: 2,
|
||||||
|
routePath: '/network/instance/detail/:instanceId/port/:id',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -587,6 +587,7 @@
|
|||||||
"DNS": "DNS",
|
"DNS": "DNS",
|
||||||
"DNS Assignment": "DNS Assignment",
|
"DNS Assignment": "DNS Assignment",
|
||||||
"DNS Name": "DNS Name",
|
"DNS Name": "DNS Name",
|
||||||
|
"DNS Nameservers": "DNS Nameservers",
|
||||||
"DPD Action": "DPD Action",
|
"DPD Action": "DPD Action",
|
||||||
"DPD Interval (sec)": "DPD Interval (sec)",
|
"DPD Interval (sec)": "DPD Interval (sec)",
|
||||||
"DPD actions controls the use of Dead Peer Detection Protocol.": "DPD actions controls the use of Dead Peer Detection Protocol.",
|
"DPD actions controls the use of Dead Peer Detection Protocol.": "DPD actions controls the use of Dead Peer Detection Protocol.",
|
||||||
@ -841,6 +842,7 @@
|
|||||||
"Enable Admin State": "Enable Admin State",
|
"Enable Admin State": "Enable Admin State",
|
||||||
"Enable Compute Host": "Enable Compute Host",
|
"Enable Compute Host": "Enable Compute Host",
|
||||||
"Enable Compute Service": "Enable Compute Service",
|
"Enable Compute Service": "Enable Compute Service",
|
||||||
|
"Enable DHCP": "Enable DHCP",
|
||||||
"Enable Domain": "Enable Domain",
|
"Enable Domain": "Enable Domain",
|
||||||
"Enable Floating IP": "Enable Floating IP",
|
"Enable Floating IP": "Enable Floating IP",
|
||||||
"Enable HealthMonitor": "Enable HealthMonitor",
|
"Enable HealthMonitor": "Enable HealthMonitor",
|
||||||
@ -1089,6 +1091,7 @@
|
|||||||
"IP Address": "IP Address",
|
"IP Address": "IP Address",
|
||||||
"IP Distribution Mode": "IP Distribution Mode",
|
"IP Distribution Mode": "IP Distribution Mode",
|
||||||
"IP Protocol": "IP Protocol",
|
"IP Protocol": "IP Protocol",
|
||||||
|
"IP Usage": "IP Usage",
|
||||||
"IP Version": "IP Version",
|
"IP Version": "IP Version",
|
||||||
"IP address allocation polls, one enter per line(e.g. 192.168.1.2,192.168.1.200)": "IP address allocation polls, one enter per line(e.g. 192.168.1.2,192.168.1.200)",
|
"IP address allocation polls, one enter per line(e.g. 192.168.1.2,192.168.1.200)": "IP address allocation polls, one enter per line(e.g. 192.168.1.2,192.168.1.200)",
|
||||||
"IP address allocation polls, one enter per line(e.g. {ip})": "IP address allocation polls, one enter per line(e.g. {ip})",
|
"IP address allocation polls, one enter per line(e.g. {ip})": "IP address allocation polls, one enter per line(e.g. {ip})",
|
||||||
@ -1781,6 +1784,7 @@
|
|||||||
"Pool Protocol": "Pool Protocol",
|
"Pool Protocol": "Pool Protocol",
|
||||||
"Pools": "Pools",
|
"Pools": "Pools",
|
||||||
"Port": "Port",
|
"Port": "Port",
|
||||||
|
"Port Count": "Port Count",
|
||||||
"Port Detail": "Port Detail",
|
"Port Detail": "Port Detail",
|
||||||
"Port Forwarding": "Port Forwarding",
|
"Port Forwarding": "Port Forwarding",
|
||||||
"Port Forwardings": "Port Forwardings",
|
"Port Forwardings": "Port Forwardings",
|
||||||
@ -2217,6 +2221,7 @@
|
|||||||
"Sub Users": "Sub Users",
|
"Sub Users": "Sub Users",
|
||||||
"Subnet": "Subnet",
|
"Subnet": "Subnet",
|
||||||
"Subnet Count": "Subnet Count",
|
"Subnet Count": "Subnet Count",
|
||||||
|
"Subnet Detail": "Subnet Detail",
|
||||||
"Subnet ID": "Subnet ID",
|
"Subnet ID": "Subnet ID",
|
||||||
"Subnet Name": "Subnet Name",
|
"Subnet Name": "Subnet Name",
|
||||||
"Subnets": "Subnets",
|
"Subnets": "Subnets",
|
||||||
@ -2858,6 +2863,7 @@
|
|||||||
"static routers": "static routers",
|
"static routers": "static routers",
|
||||||
"stop instance": "stop instance",
|
"stop instance": "stop instance",
|
||||||
"storage backend": "storage backend",
|
"storage backend": "storage backend",
|
||||||
|
"subnet": "subnet",
|
||||||
"subnets": "subnets",
|
"subnets": "subnets",
|
||||||
"suspend instance": "suspend instance",
|
"suspend instance": "suspend instance",
|
||||||
"the Republic of Abkhazia": "the Republic of Abkhazia",
|
"the Republic of Abkhazia": "the Republic of Abkhazia",
|
||||||
|
@ -587,6 +587,7 @@
|
|||||||
"DNS": "DNS",
|
"DNS": "DNS",
|
||||||
"DNS Assignment": "DNS指派",
|
"DNS Assignment": "DNS指派",
|
||||||
"DNS Name": "DNS名称",
|
"DNS Name": "DNS名称",
|
||||||
|
"DNS Nameservers": "DNS服务器",
|
||||||
"DPD Action": "DPD动作",
|
"DPD Action": "DPD动作",
|
||||||
"DPD Interval (sec)": "DPD最大延迟(秒)",
|
"DPD Interval (sec)": "DPD最大延迟(秒)",
|
||||||
"DPD actions controls the use of Dead Peer Detection Protocol.": "DPD动作控制对失效对端协议的处理方式。",
|
"DPD actions controls the use of Dead Peer Detection Protocol.": "DPD动作控制对失效对端协议的处理方式。",
|
||||||
@ -841,6 +842,7 @@
|
|||||||
"Enable Admin State": "启用管理状态",
|
"Enable Admin State": "启用管理状态",
|
||||||
"Enable Compute Host": "启用计算节点",
|
"Enable Compute Host": "启用计算节点",
|
||||||
"Enable Compute Service": "启用计算服务",
|
"Enable Compute Service": "启用计算服务",
|
||||||
|
"Enable DHCP": "DHCP 已启用",
|
||||||
"Enable Domain": "启用域",
|
"Enable Domain": "启用域",
|
||||||
"Enable Floating IP": "使用浮动IP",
|
"Enable Floating IP": "使用浮动IP",
|
||||||
"Enable HealthMonitor": "启用健康检查",
|
"Enable HealthMonitor": "启用健康检查",
|
||||||
@ -1089,6 +1091,7 @@
|
|||||||
"IP Address": "IP地址",
|
"IP Address": "IP地址",
|
||||||
"IP Distribution Mode": "IP分配模式",
|
"IP Distribution Mode": "IP分配模式",
|
||||||
"IP Protocol": "IP协议",
|
"IP Protocol": "IP协议",
|
||||||
|
"IP Usage": "IP使用情况",
|
||||||
"IP Version": "IP版本",
|
"IP Version": "IP版本",
|
||||||
"IP address allocation polls, one enter per line(e.g. 192.168.1.2,192.168.1.200)": "IP地址分配池,每行一条(例如: 192.168.1.2,192.168.1.200)",
|
"IP address allocation polls, one enter per line(e.g. 192.168.1.2,192.168.1.200)": "IP地址分配池,每行一条(例如: 192.168.1.2,192.168.1.200)",
|
||||||
"IP address allocation polls, one enter per line(e.g. {ip})": "IP地址分配池,每行一条(例如: {ip})",
|
"IP address allocation polls, one enter per line(e.g. {ip})": "IP地址分配池,每行一条(例如: {ip})",
|
||||||
@ -1781,6 +1784,7 @@
|
|||||||
"Pool Protocol": "资源池协议",
|
"Pool Protocol": "资源池协议",
|
||||||
"Pools": "",
|
"Pools": "",
|
||||||
"Port": "端口",
|
"Port": "端口",
|
||||||
|
"Port Count": "端口数量",
|
||||||
"Port Detail": "端口详情",
|
"Port Detail": "端口详情",
|
||||||
"Port Forwarding": "端口转发",
|
"Port Forwarding": "端口转发",
|
||||||
"Port Forwardings": "端口转发",
|
"Port Forwardings": "端口转发",
|
||||||
@ -2217,6 +2221,7 @@
|
|||||||
"Sub Users": "组内用户列表",
|
"Sub Users": "组内用户列表",
|
||||||
"Subnet": "子网",
|
"Subnet": "子网",
|
||||||
"Subnet Count": "子网数量",
|
"Subnet Count": "子网数量",
|
||||||
|
"Subnet Detail": "子网详情",
|
||||||
"Subnet ID": "子网ID",
|
"Subnet ID": "子网ID",
|
||||||
"Subnet Name": "子网名称",
|
"Subnet Name": "子网名称",
|
||||||
"Subnets": "子网",
|
"Subnets": "子网",
|
||||||
@ -2858,6 +2863,7 @@
|
|||||||
"static routers": "静态路由",
|
"static routers": "静态路由",
|
||||||
"stop instance": "关闭云主机",
|
"stop instance": "关闭云主机",
|
||||||
"storage backend": "存储后端",
|
"storage backend": "存储后端",
|
||||||
|
"subnet": "子网",
|
||||||
"subnets": "子网",
|
"subnets": "子网",
|
||||||
"suspend instance": "挂起云主机",
|
"suspend instance": "挂起云主机",
|
||||||
"the Republic of Abkhazia": "阿布哈兹",
|
"the Republic of Abkhazia": "阿布哈兹",
|
||||||
|
@ -16,9 +16,9 @@ import { inject, observer } from 'mobx-react';
|
|||||||
import Base from 'containers/TabDetail';
|
import Base from 'containers/TabDetail';
|
||||||
import { NetworkStore } from 'stores/neutron/network';
|
import { NetworkStore } from 'stores/neutron/network';
|
||||||
import { networkStatus } from 'resources/neutron/network';
|
import { networkStatus } from 'resources/neutron/network';
|
||||||
import Port from 'src/pages/network/containers/Port';
|
import Port from 'pages/network/containers/Port';
|
||||||
import globalRootStore from 'stores/root';
|
import globalRootStore from 'stores/root';
|
||||||
import Subnets from './Subnets';
|
import Subnet from 'pages/network/containers/Subnet';
|
||||||
import Detail from './Detail';
|
import Detail from './Detail';
|
||||||
import actionConfigs from '../actions';
|
import actionConfigs from '../actions';
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ export class NetworkDetail extends Base {
|
|||||||
{
|
{
|
||||||
title: t('Subnets'),
|
title: t('Subnets'),
|
||||||
key: 'subnets',
|
key: 'subnets',
|
||||||
component: Subnets,
|
component: Subnet,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Ports'),
|
title: t('Ports'),
|
||||||
|
@ -32,9 +32,43 @@ export class PortDetail extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get listUrl() {
|
get listUrl() {
|
||||||
|
const { networkId, subnetId, instanceId } = this.params;
|
||||||
|
if (this.isSubnetPortDetail) {
|
||||||
|
return this.getRoutePath(
|
||||||
|
'subnetDetail',
|
||||||
|
{ id: subnetId, networkId },
|
||||||
|
{ tab: 'ports' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.isNetworkPortDetail) {
|
||||||
|
return this.getRoutePath(
|
||||||
|
'networkDetail',
|
||||||
|
{ id: networkId },
|
||||||
|
{ tab: 'ports' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.isInstancePortDetail) {
|
||||||
|
return this.getRoutePath(
|
||||||
|
'instanceDetail',
|
||||||
|
{ id: instanceId },
|
||||||
|
{ tab: 'interface' }
|
||||||
|
);
|
||||||
|
}
|
||||||
return this.getRoutePath('port');
|
return this.getRoutePath('port');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isSubnetPortDetail() {
|
||||||
|
return this.path.includes('subnet');
|
||||||
|
}
|
||||||
|
|
||||||
|
get isNetworkPortDetail() {
|
||||||
|
return this.path.includes('networks') && !this.isSubnetPortDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isInstancePortDetail() {
|
||||||
|
return this.path.includes('instance');
|
||||||
|
}
|
||||||
|
|
||||||
get actionConfigs() {
|
get actionConfigs() {
|
||||||
if (this.isAdminPage) {
|
if (this.isAdminPage) {
|
||||||
return actionConfigs.adminActions;
|
return actionConfigs.adminActions;
|
||||||
|
@ -38,20 +38,29 @@ export class Port extends Base {
|
|||||||
return (
|
return (
|
||||||
this.inDetailPage &&
|
this.inDetailPage &&
|
||||||
(this.path.includes('networks/detail') ||
|
(this.path.includes('networks/detail') ||
|
||||||
this.path.includes('networks-admin/detail'))
|
this.path.includes('networks-admin/detail')) &&
|
||||||
|
!this.isSubnetDetail
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isSubnetDetail() {
|
||||||
|
return this.inDetailPage && this.path.includes('subnet');
|
||||||
|
}
|
||||||
|
|
||||||
|
get isRecycleBinDetail() {
|
||||||
|
return this.inDetailPage && this.path.includes('recycle-bin');
|
||||||
|
}
|
||||||
|
|
||||||
get isFilterByBackend() {
|
get isFilterByBackend() {
|
||||||
return true;
|
return !this.isSubnetDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isSortByBackend() {
|
get isSortByBackend() {
|
||||||
return true;
|
return this.isFilterByBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultSortKey() {
|
get defaultSortKey() {
|
||||||
return 'status';
|
return this.isFilterByBackend ? 'status' : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFetchParamsByPage = (params) => {
|
updateFetchParamsByPage = (params) => {
|
||||||
@ -65,6 +74,15 @@ export class Port extends Base {
|
|||||||
return newParams;
|
return newParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateFetchParams = (params) => {
|
||||||
|
const { id, networkId, ...rest } = params;
|
||||||
|
return {
|
||||||
|
network_id: networkId,
|
||||||
|
subnetId: id,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
get policy() {
|
get policy() {
|
||||||
return 'get_port';
|
return 'get_port';
|
||||||
}
|
}
|
||||||
@ -77,10 +95,6 @@ export class Port extends Base {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isRecycleBinDetail() {
|
|
||||||
return this.inDetailPage && this.path.includes('recycle-bin');
|
|
||||||
}
|
|
||||||
|
|
||||||
get actionConfigs() {
|
get actionConfigs() {
|
||||||
if (this.isRecycleBinDetail) {
|
if (this.isRecycleBinDetail) {
|
||||||
return emptyActionConfig;
|
return emptyActionConfig;
|
||||||
@ -141,12 +155,44 @@ export class Port extends Base {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getPortDetailRoute = () => {
|
||||||
|
if (this.isSubnetDetail) {
|
||||||
|
return {
|
||||||
|
routeName: this.getRouteName('subnetPortDetail'),
|
||||||
|
routeParamsFunc: (data) => ({
|
||||||
|
networkId: data.network_id,
|
||||||
|
subnetId: data.subnet_id,
|
||||||
|
id: data.id,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (this.isNetworkDetail) {
|
||||||
|
return {
|
||||||
|
routeName: this.getRouteName('networkPortDetail'),
|
||||||
|
routeParamsFunc: (data) => ({
|
||||||
|
networkId: data.network_id,
|
||||||
|
id: data.id,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (this.isInstanceDetail) {
|
||||||
|
return {
|
||||||
|
routeName: this.getRouteName('instancePortDetail'),
|
||||||
|
routeParamsFunc: (data) => ({
|
||||||
|
instanceId: data.device_id,
|
||||||
|
id: data.id,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { routeName: this.getRouteName('portDetail') };
|
||||||
|
};
|
||||||
|
|
||||||
getColumns = () => {
|
getColumns = () => {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t('ID/Name'),
|
title: t('ID/Name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
routeName: this.getRouteName('portDetail'),
|
...this.getPortDetailRoute(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Project ID/Name'),
|
title: t('Project ID/Name'),
|
||||||
@ -261,7 +307,7 @@ export class Port extends Base {
|
|||||||
{ label: t('DHCP Agent'), key: 'network:dhcp' },
|
{ label: t('DHCP Agent'), key: 'network:dhcp' },
|
||||||
{
|
{
|
||||||
label: t('Others'),
|
label: t('Others'),
|
||||||
key: 'network:local_ip,network:routed,network:distributed',
|
key: 'network:local_ip,network:routed,network:distributed,compute:kuryr',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('Unbounded'),
|
label: t('Unbounded'),
|
||||||
@ -269,7 +315,18 @@ export class Port extends Base {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
if (this.isSubnetDetail) {
|
||||||
|
deviceOwner.filterFunc = (value, filter) => {
|
||||||
|
if (filter === 'none') {
|
||||||
|
return !value;
|
||||||
|
}
|
||||||
|
return value && filter.includes(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!this.isInstanceDetail) {
|
||||||
ret.push(deviceOwner);
|
ret.push(deviceOwner);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
140
src/pages/network/containers/Subnet/Detail/Detail.jsx
Normal file
140
src/pages/network/containers/Subnet/Detail/Detail.jsx
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// Copyright 2022 99cloud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import Base from 'containers/BaseDetail';
|
||||||
|
|
||||||
|
export class BaseDetail extends Base {
|
||||||
|
get leftCards() {
|
||||||
|
const cards = [this.networkCard, this.baseInfoCard];
|
||||||
|
if (this.canAddNetworkIPUsageInfo) {
|
||||||
|
cards.push(this.ipUsageCard);
|
||||||
|
}
|
||||||
|
return cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canAddNetworkIPUsageInfo() {
|
||||||
|
return (
|
||||||
|
this.isAdminPage || this.currentProjectId === this.detailData.project_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get networkCard() {
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
label: t('Network Name'),
|
||||||
|
dataIndex: 'network.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Network ID'),
|
||||||
|
dataIndex: 'network.id',
|
||||||
|
render: (value) => {
|
||||||
|
const link = this.getLinkRender('networkDetail', value, {
|
||||||
|
id: value,
|
||||||
|
});
|
||||||
|
return link;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
title: t('Network Info'),
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseInfoCard() {
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
label: t('Gateway IP'),
|
||||||
|
dataIndex: 'gateway_ip',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Allocation Pools'),
|
||||||
|
dataIndex: 'allocation_pools',
|
||||||
|
render: (value) => {
|
||||||
|
const items = (value || []).map((it) => {
|
||||||
|
const { start, end } = it;
|
||||||
|
return (
|
||||||
|
<div key={`${start}-${end}`}>
|
||||||
|
{start} - {end}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return <>{items}</>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Enable DHCP'),
|
||||||
|
dataIndex: 'enable_dhcp',
|
||||||
|
valueRender: 'yesNo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Host Routes'),
|
||||||
|
dataIndex: 'host_routes',
|
||||||
|
render: (value) => {
|
||||||
|
if (!value.length) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
const lines = value.map((it) => {
|
||||||
|
const { destination, nexthop } = it;
|
||||||
|
return (
|
||||||
|
<div key={`${destination},${nexthop}`}>
|
||||||
|
{destination},{nexthop}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return <>{lines}</>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('DNS Nameservers'),
|
||||||
|
dataIndex: 'dns_nameservers',
|
||||||
|
render: (value) => {
|
||||||
|
if (!value.length) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
const lines = value.map((it) => <div key={it}>{it}</div>);
|
||||||
|
return <>{lines}</>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
title: t('Base Info'),
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get ipUsageCard() {
|
||||||
|
if (!this.canAddNetworkIPUsageInfo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
label: t('Total IPs'),
|
||||||
|
dataIndex: 'total_ips',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Used IPs'),
|
||||||
|
dataIndex: 'used_ips',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
title: t('IP Usage'),
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default inject('rootStore')(observer(BaseDetail));
|
108
src/pages/network/containers/Subnet/Detail/index.jsx
Normal file
108
src/pages/network/containers/Subnet/Detail/index.jsx
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2022 99cloud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import Base from 'containers/TabDetail';
|
||||||
|
import { SubnetStore } from 'stores/neutron/subnet';
|
||||||
|
import Port from 'pages/network/containers/Port';
|
||||||
|
import Detail from './Detail';
|
||||||
|
import actionConfigs from '../actions';
|
||||||
|
|
||||||
|
export class SubnetDetail extends Base {
|
||||||
|
get name() {
|
||||||
|
return t('subnet');
|
||||||
|
}
|
||||||
|
|
||||||
|
get policy() {
|
||||||
|
return 'get_subnet';
|
||||||
|
}
|
||||||
|
|
||||||
|
get listUrl() {
|
||||||
|
const { networkId } = this.params;
|
||||||
|
return this.getRoutePath(
|
||||||
|
'networkDetail',
|
||||||
|
{ id: networkId },
|
||||||
|
{ tab: 'subnets' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get actionConfigs() {
|
||||||
|
return actionConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFetchParams = (params) => {
|
||||||
|
return {
|
||||||
|
...params,
|
||||||
|
inDetail: true,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
get detailInfos() {
|
||||||
|
const ret = [
|
||||||
|
{
|
||||||
|
title: t('Name'),
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Project ID'),
|
||||||
|
dataIndex: 'project_id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('CIDR'),
|
||||||
|
dataIndex: 'cidr',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('IP Version'),
|
||||||
|
dataIndex: 'ip_version',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Created At'),
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
valueRender: 'toLocalTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Update At'),
|
||||||
|
dataIndex: 'updated_at',
|
||||||
|
valueRender: 'toLocalTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Description'),
|
||||||
|
dataIndex: 'description',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
get tabs() {
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
title: t('Detail'),
|
||||||
|
key: 'detail',
|
||||||
|
component: Detail,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Ports'),
|
||||||
|
key: 'ports',
|
||||||
|
component: Port,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return tabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.store = new SubnetStore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default inject('rootStore')(observer(SubnetDetail));
|
@ -15,7 +15,7 @@
|
|||||||
import { ConfirmAction } from 'containers/Action';
|
import { ConfirmAction } from 'containers/Action';
|
||||||
import globalSubnetStore from 'stores/neutron/subnet';
|
import globalSubnetStore from 'stores/neutron/subnet';
|
||||||
|
|
||||||
export default class DeleteAction extends ConfirmAction {
|
export default class Delete extends ConfirmAction {
|
||||||
get id() {
|
get id() {
|
||||||
return 'delete';
|
return 'delete';
|
||||||
}
|
}
|
@ -16,7 +16,7 @@ import { inject, observer } from 'mobx-react';
|
|||||||
import { ModalAction } from 'containers/Action';
|
import { ModalAction } from 'containers/Action';
|
||||||
import { ipValidate } from 'utils/validate';
|
import { ipValidate } from 'utils/validate';
|
||||||
import globalSubnetStore from 'stores/neutron/subnet';
|
import globalSubnetStore from 'stores/neutron/subnet';
|
||||||
import networkUtil from '../../actions/networkUtil';
|
import networkUtil from '../../Network/actions/networkUtil';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
checkAllocation_pools,
|
checkAllocation_pools,
|
@ -12,21 +12,21 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import CreateSubnet from '../../actions/CreateSubnet';
|
import Create from '../../Network/actions/CreateSubnet';
|
||||||
import DeleteAction from './DeleteSubnet';
|
import Delete from './Delete';
|
||||||
import EditSubnet from './EditSubnet';
|
import Edit from './Edit';
|
||||||
|
|
||||||
const actionConfigs = {
|
const actionConfigs = {
|
||||||
rowActions: {
|
rowActions: {
|
||||||
firstAction: EditSubnet,
|
firstAction: Edit,
|
||||||
moreActions: [
|
moreActions: [
|
||||||
{
|
{
|
||||||
action: DeleteAction,
|
action: Delete,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
batchActions: [DeleteAction],
|
batchActions: [Delete],
|
||||||
primaryActions: [CreateSubnet],
|
primaryActions: [Create],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default actionConfigs;
|
export default actionConfigs;
|
@ -12,54 +12,18 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
import { observer, inject } from 'mobx-react';
|
import { observer, inject } from 'mobx-react';
|
||||||
import Base from 'containers/List';
|
import Base from 'containers/List';
|
||||||
import { SubnetStore } from 'stores/neutron/subnet';
|
import { SubnetStore } from 'stores/neutron/subnet';
|
||||||
import { toJS } from 'mobx';
|
import actionConfigs from './actions';
|
||||||
import globalRootStore from 'stores/root';
|
|
||||||
import actionConfigs from './subnetActions';
|
|
||||||
// import { networkStatus } from 'resources/network';
|
// import { networkStatus } from 'resources/network';
|
||||||
|
|
||||||
export class Subnets extends Base {
|
export class Subnets extends Base {
|
||||||
init() {
|
init() {
|
||||||
this.store = new SubnetStore();
|
this.store = new SubnetStore();
|
||||||
const { detail: { subnet_ip_availability = [] } = {} } = this.props;
|
|
||||||
this.subnet_ip_availability = subnet_ip_availability;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataSource = () => {
|
|
||||||
const { data, filters = {}, timeFilter = {} } = this.list;
|
|
||||||
const { id, tab, ...rest } = filters;
|
|
||||||
const newFilters = rest;
|
|
||||||
let items = [];
|
|
||||||
if (this.isFilterByBackend) {
|
|
||||||
items = toJS(data);
|
|
||||||
} else {
|
|
||||||
items = (toJS(data) || []).filter((it) =>
|
|
||||||
this.filterData(it, toJS(newFilters), toJS(timeFilter))
|
|
||||||
);
|
|
||||||
this.updateList({ total: items.length });
|
|
||||||
}
|
|
||||||
const hasTransData = items.some((item) =>
|
|
||||||
this.itemInTransitionFunction(item)
|
|
||||||
);
|
|
||||||
if (hasTransData) {
|
|
||||||
this.setRefreshDataTimerTransition();
|
|
||||||
} else {
|
|
||||||
this.setRefreshDataTimerAuto();
|
|
||||||
}
|
|
||||||
const ret = items.map((item) => {
|
|
||||||
const usageDetail = this.subnet_ip_availability.find(
|
|
||||||
(i) => i.subnet_id === item.id
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
...usageDetail,
|
|
||||||
...item,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
get policy() {
|
get policy() {
|
||||||
return 'get_subnet';
|
return 'get_subnet';
|
||||||
}
|
}
|
||||||
@ -77,16 +41,16 @@ export class Subnets extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateFetchParams = () => {
|
updateFetchParams = () => {
|
||||||
const { id } = this.props.match.params;
|
|
||||||
return {
|
return {
|
||||||
network_id: id,
|
network_id: this.id,
|
||||||
|
network: this.props.detail,
|
||||||
|
all_projects: this.isAdminPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
get canAddNetworkIPUsageInfo() {
|
get canAddNetworkIPUsageInfo() {
|
||||||
return (
|
return (
|
||||||
this.isAdminPage ||
|
this.isAdminPage || this.currentProjectId === this.props.detail.project_id
|
||||||
globalRootStore.user.project.id === this.props.detail.project_id
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +60,11 @@ export class Subnets extends Base {
|
|||||||
title: t('Name'),
|
title: t('Name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
stringify: (name, record) => name || record.id,
|
stringify: (name, record) => name || record.id,
|
||||||
|
routeName: this.getRouteName('subnetDetail'),
|
||||||
|
routeParamsFunc: (data) => ({
|
||||||
|
networkId: data.network_id,
|
||||||
|
id: data.id,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('CIDR'),
|
title: t('CIDR'),
|
||||||
@ -113,11 +82,25 @@ export class Subnets extends Base {
|
|||||||
isHideable: true,
|
isHideable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// title: t('Status'),
|
title: t('Port Count'),
|
||||||
// dataIndex: 'status',
|
dataIndex: 'subnetPorts',
|
||||||
// render: value => networkStatus[value] || value,
|
isHideable: true,
|
||||||
// isHideable: true,
|
stringify: (value) => (value || []).length,
|
||||||
// }, {
|
render: (value, record) => {
|
||||||
|
const count = (value || []).length;
|
||||||
|
if (!count) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
const link = this.getLinkRender(
|
||||||
|
'subnetDetail',
|
||||||
|
count,
|
||||||
|
{ id: record.id, networkId: record.network_id },
|
||||||
|
{ tab: 'ports' }
|
||||||
|
);
|
||||||
|
return <>{link}</>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
title: t('Created At'),
|
title: t('Created At'),
|
||||||
dataIndex: 'created_at',
|
dataIndex: 'created_at',
|
||||||
valueRender: 'toLocalTime',
|
valueRender: 'toLocalTime',
|
||||||
@ -126,7 +109,7 @@ export class Subnets extends Base {
|
|||||||
];
|
];
|
||||||
if (this.canAddNetworkIPUsageInfo) {
|
if (this.canAddNetworkIPUsageInfo) {
|
||||||
ret.splice(
|
ret.splice(
|
||||||
4,
|
5,
|
||||||
0,
|
0,
|
||||||
{
|
{
|
||||||
title: t('Total IPs'),
|
title: t('Total IPs'),
|
@ -17,6 +17,7 @@ import E404 from 'pages/base/containers/404';
|
|||||||
import Network from '../containers/Network';
|
import Network from '../containers/Network';
|
||||||
import AdminNetwork from '../containers/Network/Network';
|
import AdminNetwork from '../containers/Network/Network';
|
||||||
import NetworkDetail from '../containers/Network/Detail';
|
import NetworkDetail from '../containers/Network/Detail';
|
||||||
|
import SubnetDetail from '../containers/Subnet/Detail';
|
||||||
import Router from '../containers/Router';
|
import Router from '../containers/Router';
|
||||||
import FloatingIp from '../containers/FloatingIp';
|
import FloatingIp from '../containers/FloatingIp';
|
||||||
import FloatingIpDetail from '../containers/FloatingIp/Detail';
|
import FloatingIpDetail from '../containers/FloatingIp/Detail';
|
||||||
@ -58,6 +59,46 @@ export default [
|
|||||||
component: NetworkDetail,
|
component: NetworkDetail,
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/networks/detail/:networkId/subnet/:id`,
|
||||||
|
component: SubnetDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/networks-admin/detail/:networkId/subnet/:id`,
|
||||||
|
component: SubnetDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/networks/detail/:networkId/port/:id`,
|
||||||
|
component: PortDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/networks-admin/detail/:networkId/port/:id`,
|
||||||
|
component: PortDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/networks/detail/:networkId/subnet/:subnetId/port/:id`,
|
||||||
|
component: PortDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/networks-admin/detail/:networkId/subnet/:subnetId/port/:id`,
|
||||||
|
component: PortDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/instance/detail/:instanceId/port/:id`,
|
||||||
|
component: PortDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${PATH}/instance-admin/detail/:instanceId/port/:id`,
|
||||||
|
component: PortDetail,
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
{ path: `${PATH}/router`, component: Router, exact: true },
|
{ path: `${PATH}/router`, component: Router, exact: true },
|
||||||
{ path: `${PATH}/router-admin`, component: Router, exact: true },
|
{ path: `${PATH}/router-admin`, component: Router, exact: true },
|
||||||
{
|
{
|
||||||
|
@ -59,6 +59,24 @@ export class PortStore extends Base {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get paramsFunc() {
|
||||||
|
return (params, all_projects) => {
|
||||||
|
const { current, device_owner, subnetId, networkId, ...rest } = params;
|
||||||
|
const newParams = { ...rest };
|
||||||
|
if (device_owner && isString(device_owner)) {
|
||||||
|
if (device_owner === 'none') {
|
||||||
|
newParams.device_owner = [''];
|
||||||
|
} else {
|
||||||
|
newParams.device_owner = device_owner.split(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!all_projects) {
|
||||||
|
newParams.tenant_id = this.currentProjectId;
|
||||||
|
}
|
||||||
|
return newParams;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
fixed_ips = new List();
|
fixed_ips = new List();
|
||||||
|
|
||||||
@ -150,6 +168,37 @@ export class PortStore extends Base {
|
|||||||
item.itemInList = itemContrib;
|
item.itemInList = itemContrib;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listDidFetch(items, allProjects, filters) {
|
||||||
|
if (!items.length) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
const { subnetId } = filters;
|
||||||
|
if (!subnetId) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
const newItems = [];
|
||||||
|
items.forEach((it) => {
|
||||||
|
const { fixed_ips = [] } = it;
|
||||||
|
const newFixedIps = fixed_ips.filter((ip) => ip.subnet_id === subnetId);
|
||||||
|
if (newFixedIps.length) {
|
||||||
|
const ipv4 = it.ipv4.filter((ip) =>
|
||||||
|
newFixedIps.some((newIp) => newIp.ip_address === ip)
|
||||||
|
);
|
||||||
|
const ipv6 = it.ipv6.filter((ip) =>
|
||||||
|
newFixedIps.some((newIp) => newIp.ip_address === ip)
|
||||||
|
);
|
||||||
|
newItems.push({
|
||||||
|
...it,
|
||||||
|
fixed_ips: newFixedIps,
|
||||||
|
ipv4,
|
||||||
|
ipv6,
|
||||||
|
subnet_id: subnetId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newItems;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalPortStore = new PortStore();
|
const globalPortStore = new PortStore();
|
||||||
|
@ -25,6 +25,17 @@ export class SubnetStore extends Base {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get portClient() {
|
||||||
|
return client.neutron.ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
get paramsFunc() {
|
||||||
|
return (params) => {
|
||||||
|
const { network, ...rest } = params;
|
||||||
|
return rest;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async update({ id }, values) {
|
async update({ id }, values) {
|
||||||
const {
|
const {
|
||||||
@ -47,6 +58,62 @@ export class SubnetStore extends Base {
|
|||||||
};
|
};
|
||||||
return this.submitting(this.client.update(id, { subnet: data }));
|
return this.submitting(this.client.update(id, { subnet: data }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listDidFetch(items, allProjects, filters) {
|
||||||
|
if (!items.length) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
network: { id: networkId, subnet_ip_availability: ipUsage = [] } = {},
|
||||||
|
} = filters;
|
||||||
|
const portParams = {
|
||||||
|
network_id: networkId,
|
||||||
|
};
|
||||||
|
if (!allProjects) {
|
||||||
|
portParams.tenant_id = this.currentProjectId;
|
||||||
|
}
|
||||||
|
const { ports = [] } = await this.portClient.list(portParams);
|
||||||
|
return items.map((it) => {
|
||||||
|
const ipInfo = ipUsage.find((u) => u.subnet_id === it.id);
|
||||||
|
const subnetPorts = ports.filter((port) => {
|
||||||
|
return port.fixed_ips.find((ip) => ip.subnet_id === it.id);
|
||||||
|
});
|
||||||
|
const { total_ips, used_ips } = ipInfo || {};
|
||||||
|
return {
|
||||||
|
...it,
|
||||||
|
total_ips,
|
||||||
|
used_ips,
|
||||||
|
subnetPorts,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async detailDidFetch(item, allProjects, filters) {
|
||||||
|
const { inDetail = false } = filters;
|
||||||
|
if (!inDetail) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
const { network_id, id } = item;
|
||||||
|
const networkParams = {
|
||||||
|
id: network_id,
|
||||||
|
isAdminPage: allProjects,
|
||||||
|
currentProjectId: this.currentProjectId,
|
||||||
|
};
|
||||||
|
const { NetworkStore } = require('stores/neutron/network');
|
||||||
|
const network =
|
||||||
|
await new NetworkStore().fetchDetailWithAvailabilityAndUsage(
|
||||||
|
networkParams
|
||||||
|
);
|
||||||
|
const { subnet_ip_availability = [] } = network;
|
||||||
|
const ipAvailability = subnet_ip_availability.find(
|
||||||
|
(it) => it.subnet_id === id
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
network,
|
||||||
|
...ipAvailability,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalSubnetStore = new SubnetStore();
|
const globalSubnetStore = new SubnetStore();
|
||||||
|
Loading…
Reference in New Issue
Block a user