diff --git a/src/client/manila/index.js b/src/client/manila/index.js
index 074522c9..70d78273 100644
--- a/src/client/manila/index.js
+++ b/src/client/manila/index.js
@@ -30,16 +30,13 @@ class ManilaClient extends Base {
get resources() {
return [
+ {
+ name: 'azones',
+ key: 'availability-zones',
+ },
{
key: 'shares',
responseKey: 'share',
- extendOperations: [
- {
- key: 'detail',
- method: 'get',
- isDetail: false,
- },
- ],
},
{
key: 'types',
@@ -108,6 +105,23 @@ class ManilaClient extends Base {
},
],
},
+ {
+ name: 'shareNetworks',
+ key: 'share-networks',
+ responseKey: 'share_network',
+ extendOperations: [
+ {
+ key: 'action',
+ method: 'post',
+ },
+ ],
+ subResources: [
+ {
+ key: 'subnets',
+ responseKey: 'subnet',
+ },
+ ],
+ },
];
}
}
diff --git a/src/components/Popover/Popover.jsx b/src/components/Popover/Popover.jsx
index b79368f1..d236e4af 100644
--- a/src/components/Popover/Popover.jsx
+++ b/src/components/Popover/Popover.jsx
@@ -16,6 +16,16 @@ import React, { useEffect, useState } from 'react';
import { Popover, Spin, Table } from 'antd';
import { FileTextOutlined } from '@ant-design/icons';
import PropTypes from 'prop-types';
+import { getRender } from 'utils/table';
+
+const getColumn = (column) => {
+ const { valueRender, render, ...rest } = column;
+ const newRender = render || getRender(valueRender);
+ return {
+ ...rest,
+ render: newRender,
+ };
+};
function PopupResources({ getRequests, columns }) {
const [data, setData] = useState([]);
@@ -32,7 +42,10 @@ function PopupResources({ getRequests, columns }) {
if (isLoading) {
return ;
}
- return
;
+ const currentColumns = columns.map((c) => getColumn(c));
+ return (
+
+ );
}
const IPopoverProps = {
diff --git a/src/components/Popover/PopoverNetworks.jsx b/src/components/Popover/PopoverNetworks.jsx
new file mode 100644
index 00000000..adee8434
--- /dev/null
+++ b/src/components/Popover/PopoverNetworks.jsx
@@ -0,0 +1,50 @@
+// Copyright 2021 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 { NetworkStore } from 'stores/neutron/network';
+import { networkStatus } from 'resources/network';
+import IPopover from './Popover';
+
+export default function PopoverNetworks(props) {
+ const { networkIds = [] } = props;
+ if (!networkIds.length) {
+ return null;
+ }
+ const getRequests = () => {
+ return networkIds.map((i) => new NetworkStore().fetchDetail({ id: i }));
+ };
+ const columns = [
+ {
+ dataIndex: 'name',
+ title: t('Name'),
+ },
+ {
+ title: t('External'),
+ dataIndex: 'router:external',
+ valueRender: 'yesNo',
+ },
+ {
+ title: t('Shared'),
+ dataIndex: 'shared',
+ valueRender: 'yesNo',
+ },
+ {
+ title: t('Status'),
+ dataIndex: 'status',
+ render: (value) => networkStatus[value] || '-',
+ },
+ ];
+ return ;
+}
diff --git a/src/components/Popover/PopoverSubnets.jsx b/src/components/Popover/PopoverSubnets.jsx
index a3b1004a..b11ebb88 100644
--- a/src/components/Popover/PopoverSubnets.jsx
+++ b/src/components/Popover/PopoverSubnets.jsx
@@ -16,7 +16,7 @@ import React from 'react';
import { SubnetStore } from 'stores/neutron/subnet';
import IPopover from './Popover';
-export default function PopOverSubnets(props) {
+export default function PopoverSubnets(props) {
const { subnetIds = [] } = props;
if (!subnetIds.length) {
return null;
diff --git a/src/layouts/admin-menu.jsx b/src/layouts/admin-menu.jsx
index 57260f9b..1ffd9277 100644
--- a/src/layouts/admin-menu.jsx
+++ b/src/layouts/admin-menu.jsx
@@ -437,6 +437,22 @@ const renderMenu = (t) => {
},
],
},
+ {
+ path: '/share/share-network-admin',
+ name: t('Share Network'),
+ key: 'shareNetworkAdmin',
+ level: 1,
+ endpoints: 'manilav2',
+ children: [
+ {
+ path: /^\/share\/share-network-admin\/detail\/.[^/]+$/,
+ name: t('Share Network Detail'),
+ key: 'shareNetworkDetailAdmin',
+ level: 2,
+ routePath: '/share/share-network-admin/detail/:id',
+ },
+ ],
+ },
{
path: '/share/share-instance-admin',
name: t('Share Instance'),
diff --git a/src/layouts/menu.jsx b/src/layouts/menu.jsx
index 88702b3d..6a3ede73 100644
--- a/src/layouts/menu.jsx
+++ b/src/layouts/menu.jsx
@@ -21,6 +21,7 @@ import {
HomeOutlined,
DatabaseFilled,
AppstoreOutlined,
+ SwitcherOutlined,
} from '@ant-design/icons';
const renderMenu = (t) => {
@@ -377,6 +378,30 @@ const renderMenu = (t) => {
},
],
},
+ {
+ path: '/share',
+ name: t('Share File Storage'),
+ key: 'fileStorage',
+ icon: ,
+ children: [
+ {
+ path: '/share/share-network',
+ name: t('Share Network'),
+ key: 'shareNetwork',
+ level: 1,
+ endpoints: 'manilav2',
+ children: [
+ {
+ path: /^\/share\/share-network\/detail\/.[^/]+$/,
+ name: t('Share Network Detail'),
+ key: 'shareNetworkDetail',
+ level: 2,
+ routePath: '/share/share-network/detail/:id',
+ },
+ ],
+ },
+ ],
+ },
// {
// path: '/management',
// name: t('Maintenance'),
diff --git a/src/locales/en.json b/src/locales/en.json
index 0e7feef8..35721cd0 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -415,6 +415,7 @@
"Create Security Group": "Create Security Group",
"Create Server Group": "Create Server Group",
"Create Share Group Type": "Create Share Group Type",
+ "Create Share Network": "Create Share Network",
"Create Share Type": "Create Share Type",
"Create Snapshot": "Create Snapshot",
"Create Stack": "Create Stack",
@@ -559,6 +560,7 @@
"Delete Security Group": "Delete Security Group",
"Delete Server Group": "Delete Server Group",
"Delete Share Group Type": "Delete Share Group Type",
+ "Delete Share Network": "Delete Share Network",
"Delete Share Type": "Delete Share Type",
"Delete Snapshot": "Delete Snapshot",
"Delete Static Route": "Delete Static Route",
@@ -835,6 +837,7 @@
"GRE": "GRE",
"Gabon": "Gabon",
"Gambia": "Gambia",
+ "Gateway": "Gateway",
"Gateway IP": "Gateway IP",
"Gateway Time-out (code: 504) ": "Gateway Time-out (code: 504) ",
"Gateway ip {gateway_ip} conflicts with allocation pool {pool}": "Gateway ip {gateway_ip} conflicts with allocation pool {pool}",
@@ -1298,6 +1301,7 @@
"Network Name": "Network Name",
"Network Service": "Network Service",
"Network Traffic": "Network Traffic",
+ "Network Type": "Network Type",
"Network topology page": "Network topology page",
"Networking": "Networking",
"Networking *": "Networking *",
@@ -1305,7 +1309,9 @@
"Networks": "Networks",
"Neutron Agent Detail": "Neutron Agent Detail",
"Neutron Agents": "Neutron Agents",
+ "Neutron Net": "Neutron Net",
"Neutron Service": "Neutron Service",
+ "Neutron Subnet": "Neutron Subnet",
"New": "New",
"New Availability Zone": "New Availability Zone",
"New Caledonia": "New Caledonia",
@@ -1740,6 +1746,7 @@
"Security Groups": "Security Groups",
"Security Info": "Security Info",
"Segmentation ID": "Segmentation ID",
+ "Segmentation Id": "Segmentation Id",
"Select File": "Select File",
"Select Project": "Select Project",
"Select Project Role": "Select Project Role",
@@ -1775,6 +1782,9 @@
"Share Instance": "Share Instance",
"Share Instance Detail": "Share Instance Detail",
"Share Network": "Share Network",
+ "Share Network Detail": "Share Network Detail",
+ "Share Network Subnet": "Share Network Subnet",
+ "Share Network Subnets": "Share Network Subnets",
"Share Server": "Share Server",
"Share Type": "Share Type",
"Share Type Detail": "Share Type Detail",
@@ -2286,6 +2296,7 @@
"create network": "create network",
"create router": "create router",
"create share group type": "create share group type",
+ "create share network": "create share network",
"create share type": "create share type",
"create snapshot": "create snapshot",
"create stack": "create stack",
@@ -2438,6 +2449,7 @@
"share group type": "share group type",
"share instance": "share instance",
"share instances": "share instances",
+ "share network": "share network",
"share type": "share type",
"share types": "share types",
"shelve instance": "shelve instance",
diff --git a/src/locales/zh.json b/src/locales/zh.json
index c2d2c7cd..f5b6247d 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -415,6 +415,7 @@
"Create Security Group": "创建安全组",
"Create Server Group": "创建云主机组",
"Create Share Group Type": "创建共享组类型",
+ "Create Share Network": "创建共享网络",
"Create Share Type": "创建共享类型",
"Create Snapshot": "创建快照",
"Create Stack": "创建堆栈",
@@ -559,6 +560,7 @@
"Delete Security Group": "删除安全组",
"Delete Server Group": "删除云主机组",
"Delete Share Group Type": "删除共享组类型",
+ "Delete Share Network": "删除共享网络",
"Delete Share Type": "删除共享类型",
"Delete Snapshot": "删除快照",
"Delete Static Route": "删除静态路由",
@@ -835,6 +837,7 @@
"GRE": "",
"Gabon": "加蓬",
"Gambia": "冈比亚",
+ "Gateway": "网关",
"Gateway IP": "网关IP",
"Gateway Time-out (code: 504) ": "网关超时(错误码:504 )",
"Gateway ip {gateway_ip} conflicts with allocation pool {pool}": "网关地址 {gateway_ip} 和分配地址池 {pool} 冲突",
@@ -1298,6 +1301,7 @@
"Network Name": "网络名称",
"Network Service": "网络服务",
"Network Traffic": "网络流量",
+ "Network Type": "网络类型",
"Network topology page": "网络拓扑页面",
"Networking": "创建网络中",
"Networking *": "网络 *",
@@ -1305,7 +1309,9 @@
"Networks": "网络",
"Neutron Agent Detail": "网络服务详情",
"Neutron Agents": "网络服务",
+ "Neutron Net": "Neutron网络",
"Neutron Service": "网络服务",
+ "Neutron Subnet": "Neutron子网",
"New": "新建",
"New Availability Zone": "新可用域",
"New Caledonia": "新喀里多尼亚",
@@ -1740,6 +1746,7 @@
"Security Groups": "安全组",
"Security Info": "安全信息",
"Segmentation ID": "段ID",
+ "Segmentation Id": "分段ID",
"Select File": "选择文件",
"Select Project": "选择项目",
"Select Project Role": "选择项目角色",
@@ -1775,6 +1782,9 @@
"Share Instance": "共享实例",
"Share Instance Detail": "共享实例详情",
"Share Network": "共享网络",
+ "Share Network Detail": "共享网络详情",
+ "Share Network Subnet": "共享网络子网",
+ "Share Network Subnets": "共享网络子网",
"Share Server": "共享服务器",
"Share Type": "共享类型",
"Share Type Detail": "共享类型详情",
@@ -2286,6 +2296,7 @@
"create network": "创建网络",
"create router": "创建路由",
"create share group type": "创建共享组类型",
+ "create share network": "创建共享网络",
"create share type": "创建共享类型",
"create snapshot": "创建快照",
"create stack": "创建堆栈",
@@ -2438,6 +2449,7 @@
"share group type": "共享组类型",
"share instance": "共享实例",
"share instances": "共享实例",
+ "share network": "共享网络",
"share type": "共享类型",
"share types": "共享类型",
"shelve instance": "归档云主机",
diff --git a/src/pages/share/containers/ShareNetwork/Detail/BaseDetail.jsx b/src/pages/share/containers/ShareNetwork/Detail/BaseDetail.jsx
new file mode 100644
index 00000000..d4bbfb00
--- /dev/null
+++ b/src/pages/share/containers/ShareNetwork/Detail/BaseDetail.jsx
@@ -0,0 +1,119 @@
+// Copyright 2021 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() {
+ return [this.baseInfoCard];
+ }
+
+ get rightCards() {
+ return [this.subnetInfos];
+ }
+
+ get baseInfoCard() {
+ const options = [
+ {
+ label: t('Project ID'),
+ dataIndex: 'project_id',
+ },
+ ];
+
+ return {
+ title: t('Base Info'),
+ options,
+ };
+ }
+
+ get subnetInfos() {
+ const {
+ share_network_subnets = [],
+ networks = [],
+ subnets = [],
+ } = this.detailData || {};
+ const options = share_network_subnets.map((shareSubnet, index) => {
+ return {
+ label: `${t('Share Network Subnet')} ${index + 1}`,
+ dataIndex: 'subnet',
+ render: () => {
+ const subnet = subnets[index] || {};
+ const network = networks[index] || {};
+ const infos = [
+ {
+ label: t('ID'),
+ value: shareSubnet.id,
+ },
+ {
+ label: t('Neutron Net'),
+ value: this.getLinkRender('networkDetail', network.name, {
+ id: network.id,
+ }),
+ },
+ {
+ label: t('Neutron Subnet'),
+ value: subnet.name,
+ },
+ {
+ label: t('IP Version'),
+ value: shareSubnet.ip_vesion || '-',
+ },
+ {
+ label: t('Network Type'),
+ value: shareSubnet.network_type || '-',
+ },
+ {
+ label: t('Segmentation Id'),
+ value: shareSubnet.segmentation_id || '-',
+ },
+ {
+ label: t('Availability Zone'),
+ value: shareSubnet.availability_zone || '-',
+ },
+ {
+ label: t('Cidr'),
+ value: shareSubnet.cidr || '-',
+ },
+ {
+ label: t('Gateway'),
+ value: shareSubnet.gateway || '-',
+ },
+ {
+ label: t('MTU'),
+ value: shareSubnet.mtu || '-',
+ },
+ ];
+ const items = infos.map((it) => {
+ return (
+
+ {it.label}:
+ {it.value}
+
+ );
+ });
+ return {items}
;
+ },
+ };
+ });
+ return {
+ title: t('Share Network Subnets'),
+ options,
+ labelCol: 4,
+ };
+ }
+}
+
+export default inject('rootStore')(observer(BaseDetail));
diff --git a/src/pages/share/containers/ShareNetwork/Detail/index.jsx b/src/pages/share/containers/ShareNetwork/Detail/index.jsx
new file mode 100644
index 00000000..ee0189ee
--- /dev/null
+++ b/src/pages/share/containers/ShareNetwork/Detail/index.jsx
@@ -0,0 +1,78 @@
+// Copyright 2021 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 { ShareNetworkStore } from 'stores/manila/share-network';
+import Base from 'containers/TabDetail';
+import BaseDetail from './BaseDetail';
+import actionConfigs from '../actions';
+
+export class Detail extends Base {
+ get name() {
+ return t('share network');
+ }
+
+ get policy() {
+ return 'manila:share_network:show';
+ }
+
+ get listUrl() {
+ return this.getRoutePath('shareNetwork');
+ }
+
+ get actionConfigs() {
+ return this.isAdminPage
+ ? actionConfigs.actionConfigsAdmin
+ : actionConfigs.actionConfigs;
+ }
+
+ get detailInfos() {
+ return [
+ {
+ title: t('Name'),
+ dataIndex: 'name',
+ },
+ {
+ title: t('Description'),
+ dataIndex: 'description',
+ },
+ {
+ title: t('Created At'),
+ dataIndex: 'created_at',
+ valueRender: 'toLocalTime',
+ },
+ {
+ title: t('Updated'),
+ dataIndex: 'updated_at',
+ valueRender: 'toLocalTime',
+ },
+ ];
+ }
+
+ get tabs() {
+ return [
+ {
+ title: t('Base Info'),
+ key: 'baseInfo',
+ component: BaseDetail,
+ },
+ ];
+ }
+
+ init() {
+ this.store = new ShareNetworkStore();
+ }
+}
+
+export default inject('rootStore')(observer(Detail));
diff --git a/src/pages/share/containers/ShareNetwork/actions/Create.jsx b/src/pages/share/containers/ShareNetwork/actions/Create.jsx
new file mode 100644
index 00000000..fb601bd7
--- /dev/null
+++ b/src/pages/share/containers/ShareNetwork/actions/Create.jsx
@@ -0,0 +1,157 @@
+// Copyright 2021 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 { ModalAction } from 'containers/Action';
+import globalShareNetworkStore from 'stores/manila/share-network';
+import { NetworkStore } from 'stores/neutron/network';
+import { SubnetStore } from 'stores/neutron/subnet';
+
+export class Create extends ModalAction {
+ static id = 'create';
+
+ static title = t('Create Share Network');
+
+ get name() {
+ return t('create share network');
+ }
+
+ init() {
+ this.store = globalShareNetworkStore;
+ this.networkStore = new NetworkStore();
+ this.subnetStore = new SubnetStore();
+ }
+
+ static policy = 'manila:share_network:create';
+
+ static allowed = () => Promise.resolve(true);
+
+ static get modalSize() {
+ return 'large';
+ }
+
+ getModalSize() {
+ return 'large';
+ }
+
+ get subnets() {
+ const { networkId } = this.state;
+ if (!networkId) {
+ return [];
+ }
+ return this.subnetStore.list.data || [];
+ }
+
+ getSubnets() {
+ const { networkId } = this.state;
+ if (!networkId) {
+ return;
+ }
+ this.subnetStore.fetchList({ network_id: networkId });
+ }
+
+ onNetworkChange = (value) => {
+ const { selectedRowKeys = [] } = value;
+ if (selectedRowKeys.length === 0) {
+ return;
+ }
+ this.setState(
+ {
+ networkId: selectedRowKeys[0],
+ },
+ () => {
+ this.getSubnets();
+ }
+ );
+ };
+
+ get nameForStateUpdate() {
+ return ['network'];
+ }
+
+ get formItems() {
+ const { networkId } = this.state;
+ return [
+ {
+ name: 'name',
+ label: t('Name'),
+ type: 'input-name',
+ required: true,
+ },
+ {
+ name: 'description',
+ label: t('Description'),
+ type: 'textarea',
+ },
+ {
+ name: 'network',
+ label: t('Network'),
+ type: 'network-select-table',
+ required: true,
+ onChange: this.onNetworkChange,
+ },
+ {
+ name: 'subnet',
+ label: t('Subnet'),
+ type: 'select-table',
+ data: this.subnets,
+ isLoading: networkId && this.subnetStore.list.isLoading,
+ required: true,
+ filterParams: [
+ {
+ label: t('Name'),
+ name: 'name',
+ },
+ ],
+ columns: [
+ {
+ title: t('Name'),
+ dataIndex: 'name',
+ },
+ {
+ title: t('Cidr'),
+ dataIndex: 'cidr',
+ },
+ {
+ title: t('Allocation Pools'),
+ dataIndex: 'allocation_pools',
+ render: (value) => {
+ if (!value || value.length === 0) {
+ return '-';
+ }
+ return `${value[0].start} -- ${value[0].end}`;
+ },
+ },
+ {
+ title: t('Created At'),
+ dataIndex: 'created_at',
+ valueRender: 'sinceTime',
+ },
+ ],
+ },
+ ];
+ }
+
+ onSubmit = (values) => {
+ const { network, subnet, ...rest } = values;
+ const body = {
+ neutron_net_id: network.selectedRowKeys[0],
+ neutron_subnet_id: subnet.selectedRowKeys[0],
+ ...rest,
+ };
+ return this.store.create(body);
+ };
+}
+
+export default inject('rootStore')(observer(Create));
diff --git a/src/pages/share/containers/ShareNetwork/actions/Delete.jsx b/src/pages/share/containers/ShareNetwork/actions/Delete.jsx
new file mode 100644
index 00000000..9b2fd70a
--- /dev/null
+++ b/src/pages/share/containers/ShareNetwork/actions/Delete.jsx
@@ -0,0 +1,42 @@
+// Copyright 2021 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 { ConfirmAction } from 'containers/Action';
+import globalShareNetworkStore from 'stores/manila/share-network';
+
+export default class Delete extends ConfirmAction {
+ get id() {
+ return 'delete';
+ }
+
+ get title() {
+ return t('Delete Share Network');
+ }
+
+ get buttonType() {
+ return 'danger';
+ }
+
+ get buttonText() {
+ return t('Delete');
+ }
+
+ get actionName() {
+ return t('Delete Share Network');
+ }
+
+ policy = 'manila:share_network:delete';
+
+ onSubmit = (data) => globalShareNetworkStore.delete(data);
+}
diff --git a/src/pages/share/containers/ShareNetwork/actions/Edit.jsx b/src/pages/share/containers/ShareNetwork/actions/Edit.jsx
new file mode 100644
index 00000000..217ad9a9
--- /dev/null
+++ b/src/pages/share/containers/ShareNetwork/actions/Edit.jsx
@@ -0,0 +1,63 @@
+// Copyright 2021 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 { ModalAction } from 'containers/Action';
+import globalShareNetworkStore from 'stores/manila/share-network';
+
+export class Edit extends ModalAction {
+ static id = 'edit';
+
+ static title = t('Edit');
+
+ get defaultValue() {
+ const { name, description } = this.item;
+ const value = {
+ name,
+ description,
+ };
+ return value;
+ }
+
+ static policy = 'manila:share_network:update';
+
+ static allowed = () => Promise.resolve(true);
+
+ get formItems() {
+ return [
+ {
+ name: 'name',
+ label: t('Name'),
+ type: 'input-name',
+ required: true,
+ },
+ {
+ name: 'description',
+ label: t('Description'),
+ type: 'textarea',
+ },
+ ];
+ }
+
+ init() {
+ this.store = globalShareNetworkStore;
+ }
+
+ onSubmit = (values) => {
+ const { id } = this.item;
+ return this.store.update(id, values);
+ };
+}
+
+export default inject('rootStore')(observer(Edit));
diff --git a/src/pages/share/containers/ShareNetwork/actions/index.jsx b/src/pages/share/containers/ShareNetwork/actions/index.jsx
new file mode 100644
index 00000000..7f4642ff
--- /dev/null
+++ b/src/pages/share/containers/ShareNetwork/actions/index.jsx
@@ -0,0 +1,41 @@
+// Copyright 2021 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 Create from './Create';
+import Delete from './Delete';
+import Edit from './Edit';
+
+const actionConfigs = {
+ rowActions: {
+ firstAction: Edit,
+ moreActions: [
+ {
+ action: Delete,
+ },
+ ],
+ },
+ primaryActions: [Create],
+ batchActions: [Delete],
+};
+
+const actionConfigsAdmin = {
+ rowActions: {
+ firstAction: Delete,
+ moreActions: [],
+ },
+ primaryActions: [],
+ batchActions: [],
+};
+
+export default { actionConfigs, actionConfigsAdmin };
diff --git a/src/pages/share/containers/ShareNetwork/index.jsx b/src/pages/share/containers/ShareNetwork/index.jsx
new file mode 100644
index 00000000..0a2b13c6
--- /dev/null
+++ b/src/pages/share/containers/ShareNetwork/index.jsx
@@ -0,0 +1,110 @@
+// Copyright 2021 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 { observer, inject } from 'mobx-react';
+import Base from 'containers/List';
+import globalShareNetworkStore from 'stores/manila/share-network';
+import PopoverSubnets from 'components/Popover/PopoverSubnets';
+import PopoverNetworks from 'components/Popover/PopoverNetworks';
+import actionConfigs from './actions';
+
+export class ShareNetwork extends Base {
+ init() {
+ this.store = globalShareNetworkStore;
+ }
+
+ get policy() {
+ return 'manila:share_network:detail';
+ }
+
+ get name() {
+ return t('share types');
+ }
+
+ get actionConfigs() {
+ return this.isAdminPage
+ ? actionConfigs.actionConfigsAdmin
+ : actionConfigs.actionConfigs;
+ }
+
+ getColumns = () => [
+ {
+ title: t('ID/Name'),
+ dataIndex: 'name',
+ routeName: this.getRouteName('shareNetworkDetail'),
+ },
+ {
+ title: t('Project ID/Name'),
+ dataIndex: 'project_name',
+ isHideable: true,
+ hidden: !this.isAdminPage,
+ },
+ {
+ title: t('Description'),
+ dataIndex: 'description',
+ },
+ {
+ title: t('Neutron Net'),
+ dataIndex: 'networks',
+ render: (_, record) => {
+ const { share_network_subnets: subnets = [] } = record;
+ const links = subnets.map((it) => {
+ const { neutron_net_id: id } = it;
+ const link = this.getLinkRender('networkDetail', id, { id });
+ return {link}
;
+ });
+ const networkIds = subnets.map((it) => it.neutron_net_id);
+ return (
+ <>
+ {links}
+ >
+ );
+ },
+ stringify: (_, record) => {
+ const { share_network_subnets: subnets = [] } = record;
+ return (subnets || []).map((it) => it.neutron_net_id).join(', ');
+ },
+ },
+ {
+ title: t('Neutron Subnet'),
+ dataIndex: 'share_network_subnets',
+ render: (_, record) => {
+ const { share_network_subnets: subnets = [] } = record;
+ const idItems = subnets.map((it) => {
+ const { neutron_subnet_id } = it;
+ return {neutron_subnet_id}
;
+ });
+ const ids = subnets.map((it) => it.neutron_subnet_id);
+ return (
+ <>
+ {idItems}
+ >
+ );
+ },
+ stringify: (_, record) => {
+ const { share_network_subnets: subnets = [] } = record;
+ return (subnets || []).map((it) => it.neutron_subnet_id).join(', ');
+ },
+ },
+ {
+ title: t('Created At'),
+ dataIndex: 'created_at',
+ isHideable: true,
+ valueRender: 'sinceTime',
+ },
+ ];
+}
+
+export default inject('rootStore')(observer(ShareNetwork));
diff --git a/src/pages/share/routes/index.js b/src/pages/share/routes/index.js
index 33d5c5ad..ae14f6e5 100644
--- a/src/pages/share/routes/index.js
+++ b/src/pages/share/routes/index.js
@@ -20,6 +20,8 @@ import ShareGroupType from '../containers/ShareGroupType';
import ShareGroupTypeDetail from '../containers/ShareGroupType/Detail';
import ShareInstance from '../containers/ShareInstance';
import ShareInstanceDetail from '../containers/ShareInstance/Detail';
+import ShareNetwork from '../containers/ShareNetwork';
+import ShareNetworkDetail from '../containers/ShareNetwork/Detail';
const PATH = '/share';
export default [
@@ -53,6 +55,26 @@ export default [
component: ShareInstanceDetail,
exact: true,
},
+ {
+ path: `${PATH}/share-network`,
+ component: ShareNetwork,
+ exact: true,
+ },
+ {
+ path: `${PATH}/share-network/detail/:id`,
+ component: ShareNetworkDetail,
+ exact: true,
+ },
+ {
+ path: `${PATH}/share-network-admin`,
+ component: ShareNetwork,
+ exact: true,
+ },
+ {
+ path: `${PATH}/share-network-admin/detail/:id`,
+ component: ShareNetworkDetail,
+ exact: true,
+ },
{ path: '*', component: E404 },
],
},
diff --git a/src/stores/manila/share-network.js b/src/stores/manila/share-network.js
new file mode 100644
index 00000000..338524ac
--- /dev/null
+++ b/src/stores/manila/share-network.js
@@ -0,0 +1,84 @@
+// Copyright 2021 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 { action } from 'mobx';
+import client from 'client';
+import Base from 'stores/base';
+
+export class ShareNetworkStore extends Base {
+ get client() {
+ return client.manila.shareNetworks;
+ }
+
+ get networkClient() {
+ return client.neutron.networks;
+ }
+
+ get subnetClient() {
+ return client.neutron.subnets;
+ }
+
+ get listWithDetail() {
+ return true;
+ }
+
+ get paramsFunc() {
+ return (params) => {
+ const { all_projects, ...rest } = params;
+ return {
+ ...rest,
+ all_tenants: all_projects ? 1 : 0,
+ };
+ };
+ }
+
+ async detailDidFetch(item) {
+ const { share_network_subnets: subnets = [] } = item;
+ const subnetIds = subnets.map((it) => it.neutron_subnet_id);
+ const networkIds = subnets.map((it) => it.neutron_net_id);
+ const subnetReqs = Array.from(new Set(subnetIds)).map((it) => {
+ return this.subnetClient.show(it);
+ });
+ const netReqs = Array.from(new Set(networkIds)).map((it) => {
+ return this.networkClient.show(it);
+ });
+ const subnetResults = await Promise.all(subnetReqs);
+ const netResults = await Promise.all(netReqs);
+ return {
+ ...item,
+ subnets: subnets
+ .map((it) => {
+ return subnetResults.find(
+ (s) => s.subnet.id === it.neutron_subnet_id
+ );
+ })
+ .map((it) => it.subnet),
+ networks: subnets
+ .map((it) => {
+ return netResults.find((net) => net.network.id === it.neutron_net_id);
+ })
+ .map((it) => it.network),
+ };
+ }
+
+ @action
+ update(id, data) {
+ const body = {};
+ body[this.responseKey] = data;
+ return this.submitting(this.client.update(id, body));
+ }
+}
+
+const globalShareNetworkStore = new ShareNetworkStore();
+export default globalShareNetworkStore;