mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
UI: Integrate Tungsten Fabric (#7166)
Co-authored-by: utchoang <hoangnm@unitech.vn> Co-authored-by: davidjumani <dj.davidjumani1994@gmail.com> Co-authored-by: dahn <daan@onecht.net>
This commit is contained in:
parent
f3e8f39f2b
commit
c44ba8ff3c
@ -87,11 +87,8 @@ known_categories = {
|
||||
'OpenDaylight': 'Network',
|
||||
'createServiceInstance': 'Network',
|
||||
'addGloboDnsHost': 'Network',
|
||||
'createTungstenFabricController': 'Tungsten',
|
||||
'createTungstenFabricProvider': 'Tungsten',
|
||||
'deleteTungstenFabricProvider': 'Tungsten',
|
||||
'listTungstenFabricProviders': 'Tungsten',
|
||||
'getTungstenFabricProviders': 'Tungsten',
|
||||
'configTungstenFabricService': 'Tungsten',
|
||||
'createTungstenFabricPublicNetwork': 'Tungsten',
|
||||
'synchronizeTungstenFabricData': 'Tungsten',
|
||||
@ -119,46 +116,21 @@ known_categories = {
|
||||
'createTungstenFabricFirewallRule': 'Tungsten',
|
||||
'createTungstenFabricServiceGroup': 'Tungsten',
|
||||
'createTungstenFabricAddressGroup': 'Tungsten',
|
||||
'createTungstenFabricInterfaceRouteTable': 'Tungsten',
|
||||
'createTungstenFabricNetworkRouteTable': 'Tungsten',
|
||||
'createTungstenFabricLogicalRouter': 'Tungsten',
|
||||
'createTungstenFabricRoutingPolicy': 'Tungsten',
|
||||
'addTungstenFabricFirewallPolicy': 'Tungsten',
|
||||
'addTungstenFabricFirewallRule': 'Tungsten',
|
||||
'addTungstenFabricRouteTableToInterface': 'Tungsten',
|
||||
'addTungstenFabricRouteTableToNetwork': 'Tungsten',
|
||||
'addTungstenFabricInterfaceStaticRoute': 'Tungsten',
|
||||
'addTungstenFabricNetworkStaticRoute': 'Tungsten',
|
||||
'addTungstenFabricNetworkGatewayToLogicalRouter': 'Tungsten',
|
||||
'addTungstenFabricRoutingPolicyTerm': 'Tungsten',
|
||||
'listTungstenFabricApplicationPolicySet': 'Tungsten',
|
||||
'listTungstenFabricFirewallPolicy': 'Tungsten',
|
||||
'listTungstenFabricFirewallRule': 'Tungsten',
|
||||
'listTungstenFabricServiceGroup': 'Tungsten',
|
||||
'listTungstenFabricAddressGroup': 'Tungsten',
|
||||
'listTungstenFabricInterfaceRouteTable': 'Tungsten',
|
||||
'listTungstenFabricNetworkRouteTable': 'Tungsten',
|
||||
'listTungstenFabricInterfaceStaticRoute': 'Tungsten',
|
||||
'listTungstenFabricNetworkStaticRoute': 'Tungsten',
|
||||
'listTungstenFabricLogicalRouter': 'Tungsten',
|
||||
'listTungstenFabricRoutingPolicy': 'Tungsten',
|
||||
'deleteTungstenFabricApplicationPolicySet': 'Tungsten',
|
||||
'deleteTungstenFabricFirewallPolicy': 'Tungsten',
|
||||
'deleteTungstenFabricFirewallRule': 'Tungsten',
|
||||
'deleteTungstenFabricAddressGroup': 'Tungsten',
|
||||
'deleteTungstenFabricServiceGroup': 'Tungsten',
|
||||
'deleteTungstenFabricLogicalRouter': 'Tungsten',
|
||||
'removeTungstenFabricFirewallPolicy': 'Tungsten',
|
||||
'removeTungstenFabricFirewallRule': 'Tungsten',
|
||||
'removeTungstenFabricInterfaceRouteTable': 'Tungsten',
|
||||
'removeTungstenFabricNetworkRouteTable': 'Tungsten',
|
||||
'removeTungstenFabricInterfaceStaticRoute': 'Tungsten',
|
||||
'removeTungstenFabricNetworkStaticRoute': 'Tungsten',
|
||||
'removeTungstenFabricRouteTableFromInterface': 'Tungsten',
|
||||
'removeTungstenFabricRouteTableFromNetwork': 'Tungsten',
|
||||
'removeTungstenFabricNetworkGatewayFromLogicalRouter': 'Tungsten',
|
||||
'removeTungstenFabricRoutingPolicy': 'Tungsten',
|
||||
'removeTungstenFabricRoutingPolicyTerm': 'Tungsten',
|
||||
'updateTungstenFabricLBHealthMonitor': 'Tungsten',
|
||||
'listTungstenFabricLBHealthMonitor': 'Tungsten',
|
||||
'Vpn': 'VPN',
|
||||
|
||||
@ -68,10 +68,12 @@
|
||||
"label.action.delete.domain": "Delete domain",
|
||||
"label.action.delete.egress.firewall": "Delete egress firewall rule",
|
||||
"label.action.delete.firewall": "Delete firewall rule",
|
||||
"label.action.delete.interface.static.route": "Remove Tungsten Fabric interface static route",
|
||||
"label.action.delete.ip.range": "Delete IP range",
|
||||
"label.action.delete.iso": "Delete ISO",
|
||||
"label.action.delete.load.balancer": "Delete load balancer rule",
|
||||
"label.action.delete.network": "Delete network",
|
||||
"label.action.delete.network.static.route": "Remove Tungsten Fabric network static route",
|
||||
"label.action.delete.network.permission": "Delete network permission",
|
||||
"label.action.delete.node": "Delete node",
|
||||
"label.action.delete.physical.network": "Delete physical network",
|
||||
@ -83,6 +85,7 @@
|
||||
"label.action.delete.snapshot": "Delete snapshot",
|
||||
"label.action.delete.system.service.offering": "Delete system service offering",
|
||||
"label.action.delete.template": "Delete template",
|
||||
"label.action.delete.tungsten.router.table": "Remove Tungsten Fabric route table from network",
|
||||
"label.action.delete.user": "Delete user",
|
||||
"label.action.delete.volume": "Delete volume",
|
||||
"label.action.delete.zone": "Delete zone",
|
||||
@ -118,6 +121,7 @@
|
||||
"label.action.force.reconnect": "Force reconnect",
|
||||
"label.action.generate.keys": "Generate keys",
|
||||
"label.action.get.diagnostics": "Get diagnostics data",
|
||||
"label.action.health.monitor": "Health monitor",
|
||||
"label.action.image.store.read.only": "Make image store read-only",
|
||||
"label.action.image.store.read.write": "Make image store read-write",
|
||||
"label.action.import.export.instances": "Import-Export instances",
|
||||
@ -143,6 +147,10 @@
|
||||
"label.action.release.ip": "Release IP",
|
||||
"label.action.release.reserved.ip": "Release reserved IP",
|
||||
"label.action.remove.host": "Remove host",
|
||||
"label.action.remove.logical.router": "Remove Logical Router",
|
||||
"label.action.remove.network.policy": "Remove Network Policy",
|
||||
"label.action.remove.router.table.from.interface": "Remove Tungsten Fabric route table from interface",
|
||||
"label.action.remove.tungsten.routing.policy": "Remove Tungsten-Fabric routing policy from network",
|
||||
"label.action.remove.nic": "Remove NIC",
|
||||
"label.action.reserve.ip": "Reserve Public IP",
|
||||
"label.action.reset.network.permissions": "Reset network permissions",
|
||||
@ -167,6 +175,7 @@
|
||||
"label.action.unmanage.virtualmachine": "Unmanage VM",
|
||||
"label.action.update.offering.access": "Update offering access",
|
||||
"label.action.update.resource.count": "Update resource count",
|
||||
"label.action.value": "Action/Value",
|
||||
"label.action.userdata.reset": "Reset userdata",
|
||||
"label.action.vmsnapshot.create": "Take VM snapshot",
|
||||
"label.action.vmsnapshot.delete": "Delete VM snapshot",
|
||||
@ -194,6 +203,7 @@
|
||||
"label.add.egress.rule": "Add egress rule",
|
||||
"label.add.f5.device": "Add F5 device",
|
||||
"label.add.firewall": "Add firewall rule",
|
||||
"label.add.firewallrule": "Add Firewall Rule",
|
||||
"label.add.guest.network": "Add guest network",
|
||||
"label.add.host": "Add host",
|
||||
"label.add.ingress.rule": "Add ingress rule",
|
||||
@ -205,6 +215,7 @@
|
||||
"label.add.kubernetes.cluster": "Add Kubernetes cluster",
|
||||
"label.add.ldap.account": "Add LDAP account",
|
||||
"label.add.list.name": "ACL List name",
|
||||
"label.add.logical.router": "Add Logical Router to this network",
|
||||
"label.add.more": "Add more",
|
||||
"label.add.netscaler.device": "Add Netscaler device",
|
||||
"label.add.network": "Add network",
|
||||
@ -221,12 +232,15 @@
|
||||
"label.add.param": "Add param",
|
||||
"label.add.physical.network": "Add physical network",
|
||||
"label.add.pod": "Add pod",
|
||||
"label.add.prefix": "Add prefix",
|
||||
"label.add.policy": "Add policy",
|
||||
"label.add.primary.storage": "Add primary storage",
|
||||
"label.add.private.gateway": "Add private gateway",
|
||||
"label.add.resources": "Add resources",
|
||||
"label.add.role": "Add role",
|
||||
"label.add.route": "Add route",
|
||||
"label.add.router.table.to.instance": "Add router table to this instance",
|
||||
"label.add.routing.policy": "Add routing policy",
|
||||
"label.add.rule": "Add rule",
|
||||
"label.add.secondary.ip": "Add secondary IP",
|
||||
"label.add.secondary.storage": "Add secondary storage",
|
||||
@ -235,8 +249,24 @@
|
||||
"label.add.srx.device": "Add SRX device",
|
||||
"label.add.static.route": "Add static route",
|
||||
"label.add.system.service.offering": "Add system service offering",
|
||||
"label.add.term.then": "Add term",
|
||||
"label.add.traffic": "Add traffic",
|
||||
"label.add.traffic.type": "Add traffic type",
|
||||
"label.add.tungsten.address.group": "Add Address Group",
|
||||
"label.add.tungsten.fabric.route": "Add Tungsten Fabric network routing table",
|
||||
"label.add.tungsten.firewall.policy": "Add Firewall Policy",
|
||||
"label.add.tungsten.firewall.rule": "Add Firewall Rule",
|
||||
"label.add.tungsten.interface.route": "Add Tungsten Fabric interface routing table",
|
||||
"label.add.tungsten.interface.static.route": "Add Tungsten Fabric interface static route",
|
||||
"label.add.tungsten.logical.route": "Add Logical Router",
|
||||
"label.add.tungsten.network.static.route": "Add Tungsten Fabric network static route",
|
||||
"label.add.tungsten.policy": "Add Policy",
|
||||
"label.add.tungsten.policy.set": "Add Application Policy Set",
|
||||
"label.add.tungsten.router.table": "Add route table to this network",
|
||||
"label.add.tungsten.routing.policy": "Add routing policy to this network",
|
||||
"label.add.tungsten.service.group": "Add Service Group",
|
||||
"label.add.tungsten.tag": "Add Tag",
|
||||
"label.add.tungsten.tag.type": "Add Tag Type",
|
||||
"label.add.user": "Add user",
|
||||
"label.add.upstream.ipv6.routes": "Add upstream IPv6 routes",
|
||||
"label.add.vm": "Add VM",
|
||||
@ -252,6 +282,7 @@
|
||||
"label.adding": "Adding",
|
||||
"label.adding.user": "Adding user...",
|
||||
"label.address": "Address",
|
||||
"label.address.group": "Address group",
|
||||
"label.admin": "Domain admin",
|
||||
"label.advanced": "Advanced",
|
||||
"label.advanced.mode": "Advanced mode",
|
||||
@ -280,8 +311,6 @@
|
||||
"label.annotation": "Comment",
|
||||
"label.annotations": "Comments",
|
||||
"label.adminsonly": "Only visible to administrators",
|
||||
"label.entityid": "Entity",
|
||||
"label.entitytype": "Entity type",
|
||||
"label.annotation.everyone": "Visible to everyone",
|
||||
"label.anti.affinity": "Anti-affinity",
|
||||
"label.anti.affinity.group": "Anti-affinity group",
|
||||
@ -289,7 +318,11 @@
|
||||
"label.apikey": "API key",
|
||||
"label.app.cookie": "AppCookie",
|
||||
"label.app.name": "CloudStack",
|
||||
"label.application.policy.set": "Application Policy Set",
|
||||
"label.apply": "Apply",
|
||||
"label.apply.tungsten.firewall.policy": "Apply Firewall Policy",
|
||||
"label.apply.tungsten.network.policy": "Apply Network Policy",
|
||||
"label.apply.tungsten.tag": "Apply tag",
|
||||
"label.archive": "Archive",
|
||||
"label.archive.alerts": "Archive alerts",
|
||||
"label.archive.events": "Archive events",
|
||||
@ -312,6 +345,7 @@
|
||||
"label.auto.assign": "Automatically assign",
|
||||
"label.auto.assign.diskoffering.disk.size": "Automatically assign offering matching the disk size",
|
||||
"label.auto.assign.random.ip": "Automatically assign a random IP address",
|
||||
"label.automigrate.volume": "Auto migrate volume to another storage pool if required",
|
||||
"label.autoscale.vm.groups": "AutoScale VM Groups",
|
||||
"label.autoscale.vm.profile": "AutoScale VM Profile",
|
||||
"label.autoscalingenabled": "Auto scaling",
|
||||
@ -377,8 +411,8 @@
|
||||
"label.change.affinity": "Change affinity",
|
||||
"label.change.ip.address": "Change IP address",
|
||||
"label.change.ipaddress": "Change IP address for NIC",
|
||||
"label.change.service.offering": "Change service offering",
|
||||
"label.change.offering.for.volume": "Change disk offering for the volume",
|
||||
"label.change.service.offering": "Change service offering",
|
||||
"label.character": "Character",
|
||||
"label.checksum": "Checksum",
|
||||
"label.choose.resource.icon": "Choose icon",
|
||||
@ -395,8 +429,8 @@
|
||||
"label.cks.cluster.size": "Cluster size (Worker nodes)",
|
||||
"label.cleanup": "Clean up",
|
||||
"label.clear": "Clear",
|
||||
"label.clear.notification": "Clear notification",
|
||||
"label.clear.list": "Clear list",
|
||||
"label.clear.notification": "Clear notification",
|
||||
"label.close": "Close",
|
||||
"label.cloudian.storage": "Cloudian storage",
|
||||
"label.cluster": "Cluster",
|
||||
@ -413,15 +447,17 @@
|
||||
"label.columns": "Columns",
|
||||
"label.comma.separated.list.description": "Enter comma-separated list of commands",
|
||||
"label.comments": "Comments",
|
||||
"label.communities": "Communities",
|
||||
"label.community": "Community",
|
||||
"label.complete": "Complete",
|
||||
"label.compute": "Compute",
|
||||
"label.compute.offerings": "Compute offerings",
|
||||
"label.computeonly.offering": "Compute only disk offering",
|
||||
"label.computeonly.offering.tooltip": "Option to specify root disk related information in the compute offering or to directly link a disk offering to the compute offering",
|
||||
"label.compute.offerings": "Compute offerings",
|
||||
"label.conditions": "Conditions",
|
||||
"label.configuration": "Configuration",
|
||||
"label.configure": "Configure",
|
||||
"label.configure.health.monitor": "Configure Health Monitor",
|
||||
"label.configure.ldap": "Configure LDAP",
|
||||
"label.configure.ovs": "Configure Ovs",
|
||||
"label.configure.sticky.policy": "Configure sticky policy",
|
||||
@ -432,7 +468,17 @@
|
||||
"label.confirm.delete.loadbalancer.rules": "Please confirm you wish to delete the selected load balancing rules.",
|
||||
"label.confirm.delete.portforward.rules": "Please confirm you wish to delete the selected port-forward rules.",
|
||||
"label.confirm.delete.templates": "Please confirm you wish to delete the selected templates.",
|
||||
"label.confirm.delete.tungsten.address.group": "Please confirm that you would like to delete this Address Group",
|
||||
"label.confirm.delete.tungsten.firewall.policy": "Please confirm that you would like to delete this Firewall Policy",
|
||||
"label.confirm.delete.tungsten.policy": "Please confirm that you would like to delete this Policy",
|
||||
"label.confirm.delete.tungsten.policy.set": "Please confirm that you would like to delete this Application Policy Set",
|
||||
"label.confirm.delete.tungsten.service.group": "Please confirm that you would like to delete this Service Group",
|
||||
"label.confirm.delete.tungsten.tag": "Please confirm that you would like to delete this Tag",
|
||||
"label.confirm.delete.tungsten.tag.type": "Please confirm that you would like to delete this Tag Type",
|
||||
"label.confirm.release.public.ip.addresses": "Please confirm you wish to release the selected public IP addresses.",
|
||||
"label.confirm.remove.logical.router": "Please confirm that you would like to delete this Logical Router",
|
||||
"label.confirm.remove.network.route.table": "Please confirm that you would like to delete this network Route Table",
|
||||
"label.confirm.remove.route.table": "Please confirm that you would like to delete this Interface Route Table",
|
||||
"label.confirmacceptinvitation": "Please confirm you wish to join this project.",
|
||||
"label.confirmation": "Confirmation",
|
||||
"label.confirmdeclineinvitation": "Are you sure you want to decline this project invitation?",
|
||||
@ -477,6 +523,7 @@
|
||||
"label.create.nfs.secondary.staging.storage": "Create NFS secondary staging storage",
|
||||
"label.create.project": "Create project",
|
||||
"label.create.project.role": "Create project role",
|
||||
"label.create.routing.policy": "Create Routing Policy",
|
||||
"label.create.site.vpn.connection": "Create site-to-site VPN connection",
|
||||
"label.create.site.vpn.gateway": "Create site-to-site VPN gateway",
|
||||
"label.create.snapshot.for.volume": "Created snapshot for volume",
|
||||
@ -488,6 +535,7 @@
|
||||
"label.create.tier.name.description": "A unique name for the tier.",
|
||||
"label.create.tier.netmask.description": "The tier's netmask. For example 255.255.255.0",
|
||||
"label.create.tier.networkofferingid.description": "The network offering for the tier.",
|
||||
"label.create.tungsten.routing.policy": "Create Tungsten-Fabric routing policy",
|
||||
"label.create.user": "Create user",
|
||||
"label.create.vpn.connection": "Create VPN connection",
|
||||
"label.created": "Created",
|
||||
@ -559,6 +607,15 @@
|
||||
"label.delete.snapshot.policy": "Delete snapshot policy",
|
||||
"label.delete.srx": "Delete SRX",
|
||||
"label.delete.sslcertificate": "Delete SSL certificate",
|
||||
"label.delete.tag": "Remove tag",
|
||||
"label.delete.term": "Delete term",
|
||||
"label.delete.tungsten.address.group": "Delete Address Group",
|
||||
"label.delete.tungsten.fabric.tag": "Delete Tag",
|
||||
"label.delete.tungsten.fabric.tag.type": "Delete Tag type",
|
||||
"label.delete.tungsten.firewall.policy": "Delete Firewall Policy",
|
||||
"label.delete.tungsten.policy": "Delete Policy",
|
||||
"label.delete.tungsten.policy.set": "Delete Policy Set",
|
||||
"label.delete.tungsten.service.group": "Delete Service Group",
|
||||
"label.delete.volumes": "Data volumes to be deleted",
|
||||
"label.delete.vpn.connection": "Delete VPN connection",
|
||||
"label.delete.vpn.customer.gateway": "Delete VPN customer gateway",
|
||||
@ -578,11 +635,21 @@
|
||||
"label.desc.importexportinstancewizard": "Import and export instances to/from an existing VMware cluster.",
|
||||
"label.desc.usage.stats": "Usage Server Statistics",
|
||||
"label.description": "Description",
|
||||
"label.destaddressgroupuuid": "Destination Address Group",
|
||||
"label.destcidr": "Destination CIDR",
|
||||
"label.destendport": "Destination End Port",
|
||||
"label.destination": "Destination",
|
||||
"label.destinationphysicalnetworkid": "Destination physical network ID",
|
||||
"label.destinationtype": "Destination Type",
|
||||
"label.destipprefix": "Destination Network Address",
|
||||
"label.destipprefixlen": "Destination Prefix Length",
|
||||
"label.destnetwork": "Destination Network",
|
||||
"label.destnetworkuuid": "Network",
|
||||
"label.destport": "Destination Ports",
|
||||
"label.destroy": "Destroy",
|
||||
"label.destroy.router": "Destroy router",
|
||||
"label.deststartport": "Destination Start Port",
|
||||
"label.desttaguuid": "Destination Tag",
|
||||
"label.details": "Details",
|
||||
"label.deviceid": "Device ID",
|
||||
"label.devices": "Devices",
|
||||
@ -590,6 +657,7 @@
|
||||
"label.direct.attached.public.ip": "Direct attached public IP",
|
||||
"label.direct.ips": "Shared network IPs",
|
||||
"label.directdownload": "Direct download",
|
||||
"label.direction": "Direction",
|
||||
"label.disable.autoscale.vmgroup": "Disable AutoScale VM Group",
|
||||
"label.disable.host": "Disable host",
|
||||
"label.disable.network.offering": "Disable network offering",
|
||||
@ -620,12 +688,10 @@
|
||||
"label.diskoffering": "Disk offering",
|
||||
"label.diskofferingdisplaytext": "Disk offering",
|
||||
"label.diskofferingid": "Disk offering",
|
||||
"label.diskofferingstrictness": "Disk offering strictness",
|
||||
"label.disksize": "Disk size (in GB)",
|
||||
"label.disksizeallocated": "Disk allocated",
|
||||
"label.disksizeallocatedgb": "Allocated",
|
||||
"label.disksizefree": "Disk free",
|
||||
"label.disksizestrictness": "Disk size strictness",
|
||||
"label.disksizetotal": "Disk total",
|
||||
"label.disksizetotalgb": "Total",
|
||||
"label.disksizeunallocatedgb": "Unallocated",
|
||||
@ -668,6 +734,8 @@
|
||||
"label.duration.7days": "7 days",
|
||||
"label.dynamicscalingenabled": "Dynamic scaling enabled",
|
||||
"label.dynamicscalingenabled.tooltip": "VM can dynamically scale only when dynamic scaling is enabled on template, service offering and global setting.",
|
||||
"label.diskofferingstrictness": "Disk offering strictness",
|
||||
"label.disksizestrictness": "Disk size strictness",
|
||||
"label.edge": "Edge",
|
||||
"label.edge.zone": "Edge Zone",
|
||||
"label.edit": "Edit",
|
||||
@ -709,6 +777,8 @@
|
||||
"label.endpoint": "Endpoint",
|
||||
"label.endport": "End port",
|
||||
"label.enter.token": "Enter token",
|
||||
"label.entityid": "Entity",
|
||||
"label.entitytype": "Entity Type",
|
||||
"label.error": "Error",
|
||||
"label.error.caught": "Error caught",
|
||||
"label.error.code": "Error code",
|
||||
@ -747,13 +817,18 @@
|
||||
"label.fetch.latest": "Fetch latest",
|
||||
"label.files": "Alternate files to retrieve",
|
||||
"label.filter": "Filter",
|
||||
"label.filter.annotations.self": "Created by me",
|
||||
"label.filter.annotations.all": "All comments",
|
||||
"label.filter.annotations.self": "Created by me",
|
||||
"label.filterby": "Filter by",
|
||||
"label.fingerprint": "FingerPrint",
|
||||
"label.finish": "Finish",
|
||||
"label.firewall": "Firewall",
|
||||
"label.firewall.policy": "Firewall Policy",
|
||||
"label.firewallpolicy": "Firewall Policy",
|
||||
"label.firewallrule": "Firewall rule",
|
||||
"label.firewallruleuuid": "Firewall Rule",
|
||||
"label.firstname": "First name",
|
||||
"label.firstname.lower": "firstname",
|
||||
"label.fix.errors": "Fix errors",
|
||||
"label.fixed": "Fixed offering",
|
||||
"label.for": "for",
|
||||
@ -881,6 +956,8 @@
|
||||
"label.instancename": "Internal name",
|
||||
"label.instanceport": "Instance port",
|
||||
"label.instances": "Instances",
|
||||
"label.interface.route.table": "Interface Route Table",
|
||||
"label.interface.router.table": "Interface Router Table",
|
||||
"label.intermediate.certificate": "Intermediate certificate",
|
||||
"label.internal.dns.1": "Internal DNS 1",
|
||||
"label.internal.dns.2": "Internal DNS 2",
|
||||
@ -923,6 +1000,8 @@
|
||||
"label.ip6gateway": "IPv6 Gateway",
|
||||
"label.ipaddress": "IP Address",
|
||||
"label.iplimit": "Public IP Limits",
|
||||
"label.ipprefix": "IP Prefix",
|
||||
"label.ipprefixlen": "IP Prefix Length",
|
||||
"label.ips": "IPs",
|
||||
"label.ipsecpsk": "IPsec preshared-Key",
|
||||
"label.iptotal": "Total of IP Addresses",
|
||||
@ -1068,6 +1147,7 @@
|
||||
"label.macaddresschanges": "MAC address changes",
|
||||
"label.maclearning": "MAC learning",
|
||||
"label.macos": "MacOS",
|
||||
"label.majorsequence": "Major Sequence",
|
||||
"label.make": "Make",
|
||||
"label.make.project.owner": "Make account project owner",
|
||||
"label.make.user.project.owner": "Make user project owner",
|
||||
@ -1081,6 +1161,7 @@
|
||||
"label.management.server": "Management server",
|
||||
"label.management.servers": "Management servers",
|
||||
"label.managementservers": "Number of management servers",
|
||||
"label.matchall": "Match all",
|
||||
"label.max.primary.storage": "Max. primary (GiB)",
|
||||
"label.max.secondary.storage": "Max. secondary (GiB)",
|
||||
"label.maxcpu": "Max. CPU cores",
|
||||
@ -1150,10 +1231,18 @@
|
||||
"label.minmaxiops": "Min IOPS / Max IOPS",
|
||||
"label.minmembers": "Min members",
|
||||
"label.minmemory": "Min memory (in MB)",
|
||||
"label.minorsequence": "Minor Sequence",
|
||||
"label.minsize": "Minimum size",
|
||||
"label.minute.past.hour": "minute(s) past the hour",
|
||||
"label.monday": "Monday",
|
||||
"label.monitor": "Monitor",
|
||||
"label.monitor.expected.code": "Expected HTTP Status Code",
|
||||
"label.monitor.http.method": "HTTP Method",
|
||||
"label.monitor.interval": "Health check interval (sec)",
|
||||
"label.monitor.retry": "Retry count before markdown",
|
||||
"label.monitor.timeout": "Timeout (sec)",
|
||||
"label.monitor.type": "Monitor Type",
|
||||
"label.monitor.url": "URL Path",
|
||||
"label.monthly": "Monthly",
|
||||
"label.more.access.dashboard.ui": "More about accessing dashboard UI",
|
||||
"label.move.down.row": "Move down one row",
|
||||
@ -1181,6 +1270,9 @@
|
||||
"label.network.name": "Network name",
|
||||
"label.network.offering": "Network offering",
|
||||
"label.network.offerings": "Network offerings",
|
||||
"label.network.policy": "Network Policy",
|
||||
"label.network.route.table": "Network route table",
|
||||
"label.network.routing.policy": "Network routing policy",
|
||||
"label.network.permissions": "Network permissions",
|
||||
"label.network.selection": "Network selection",
|
||||
"label.network.service.providers": "Network service providers",
|
||||
@ -1326,6 +1418,8 @@
|
||||
"label.podid": "Pod",
|
||||
"label.podname": "Pod name",
|
||||
"label.pods": "Pods",
|
||||
"label.policy": "Policy",
|
||||
"label.policyuuid": "Network Policy",
|
||||
"label.port": "Port",
|
||||
"label.port.range": "Port range",
|
||||
"label.portforwarding": "Port forwarding",
|
||||
@ -1337,6 +1431,7 @@
|
||||
"label.powerstate": "Power state",
|
||||
"label.preferred": "Preferred",
|
||||
"label.prefix": "Prefix",
|
||||
"label.prefix.type": "Prefix type",
|
||||
"label.presetup": "PreSetup",
|
||||
"label.prev": "Prev",
|
||||
"label.previous": "Previous",
|
||||
@ -1461,16 +1556,22 @@
|
||||
"label.remove": "Remove",
|
||||
"label.remove.annotation": "Remove comment",
|
||||
"label.remove.egress.rule": "Remove egress rule",
|
||||
"label.remove.interface.route.table": "Remove Tungsten interface route table",
|
||||
"label.remove.ip.range": "Remove IP range",
|
||||
"label.remove.ldap": "Remove LDAP",
|
||||
"label.remove.logical.network": "Remove Network from logical router",
|
||||
"label.remove.logical.router": "Remove logical router",
|
||||
"label.remove.network.offering": "Remove network offering",
|
||||
"label.remove.network.route.table": "Remove Tungsten Fabric network routing table",
|
||||
"label.remove.pf": "Remove port forwarding rule",
|
||||
"label.remove.policy": "Remove policy",
|
||||
"label.remove.project.account": "Remove account from project",
|
||||
"label.remove.project.role": "Remove project role",
|
||||
"label.remove.project.user": "Remove user from project",
|
||||
"label.remove.routing.policy": "Remove Tungsten-Fabric routing policy",
|
||||
"label.remove.rule": "Remove rule",
|
||||
"label.remove.ssh.key.pair": "Remove SSH Key pair",
|
||||
"label.remove.tungsten.tag": "Remove Tag",
|
||||
"label.remove.user.data": "Remove userdata",
|
||||
"label.remove.vm.from.lb": "Remove VM from load balancer rule",
|
||||
"label.remove.vmware.datacenter": "Remove VMware Datacenter",
|
||||
@ -1522,6 +1623,9 @@
|
||||
"label.rootdiskcontrollertype": "Root disk controller",
|
||||
"label.rootdiskcontrollertypekvm": "Root disk controller",
|
||||
"label.rootdisksize": "Root disk size (GB)",
|
||||
"label.routenexthop": "Route next hop",
|
||||
"label.routenexthoptype": "Route next hop type",
|
||||
"label.routeprefix": "Route prefix",
|
||||
"label.router.health.check.last.updated": "Last updated",
|
||||
"label.router.health.check.name": "Check name",
|
||||
"label.router.health.check.success": "Success",
|
||||
@ -1530,6 +1634,9 @@
|
||||
"label.routerip": "IPv4 address for the VR in this shared network.",
|
||||
"label.routeripv6": "IPv6 address for the VR in this shared network.",
|
||||
"label.resourcegroup": "Resource group",
|
||||
"label.routing.policy": "Routing policy",
|
||||
"label.routing.policy.terms": "Routing policy terms",
|
||||
"label.routing.policy.terms.then": "Routing policy terms then",
|
||||
"label.rule": "Rule",
|
||||
"label.rule.number": "Rule number",
|
||||
"label.rules": "Rules",
|
||||
@ -1601,10 +1708,12 @@
|
||||
"label.semanticversion": "Semantic version",
|
||||
"label.sent": "Date",
|
||||
"label.sentbytes": "Bytes sent",
|
||||
"label.sequence": "Sequence",
|
||||
"label.server": "Server",
|
||||
"label.server.certificate": "Server certificate",
|
||||
"label.service.connectivity.distributedroutercapabilitycheckbox": "Distributed router",
|
||||
"label.service.connectivity.regionlevelvpccapabilitycheckbox": "Region level VPC",
|
||||
"label.service.group": "Service group",
|
||||
"label.service.lb.elasticlbcheckbox": "Elastic LB",
|
||||
"label.service.lb.inlinemodedropdown": "Mode",
|
||||
"label.service.lb.lbisolationdropdown": "LB isolation",
|
||||
@ -1613,6 +1722,7 @@
|
||||
"label.service.offering": "Service offering",
|
||||
"label.service.staticnat.associatepublicip": "Associate public IP",
|
||||
"label.service.staticnat.elasticipcheckbox": "Elastic IP",
|
||||
"label.servicegroupuuid": "Service Group",
|
||||
"label.servicelist": "Services",
|
||||
"label.serviceofferingid": "Compute offering",
|
||||
"label.serviceofferingname": "Compute offering",
|
||||
@ -1655,10 +1765,19 @@
|
||||
"label.sourcenatsupported": "Source NAT supported",
|
||||
"label.sourcenattype": "Supported source NAT type",
|
||||
"label.sourceport": "Source port",
|
||||
"label.sourcetype": "Source type",
|
||||
"label.specifyipranges": "Specify IP ranges",
|
||||
"label.specifyvlan": "Specify VLAN",
|
||||
"label.splitconnections": "Split connections",
|
||||
"label.sr.name": "SR Name-Label",
|
||||
"label.srcaddressgroupuuid": "Source Address Group",
|
||||
"label.srcendport": "Source End Port",
|
||||
"label.srcipprefix": "Source Network Address",
|
||||
"label.srcipprefixlen": "Source Prefix Length",
|
||||
"label.srcnetwork": "Source Network",
|
||||
"label.srcnetworkuuid": "Network",
|
||||
"label.srcstartport": "Source Start Port",
|
||||
"label.srctaguuid": "Source Tag",
|
||||
"label.srx": "SRX",
|
||||
"label.srx.firewall": "Juniper SRX firewall",
|
||||
"label.ssh.key.pairs": "SSH key pairs",
|
||||
@ -1757,10 +1876,14 @@
|
||||
"label.systemtotalcpucycles": "Total CPU capacity for all cores in MHz",
|
||||
"label.systemvm": "System VM",
|
||||
"label.systemvmtype": "System VM type",
|
||||
"label.tag": "Tag",
|
||||
"label.tag.key": "Tag key",
|
||||
"label.tag.value": "Tag value",
|
||||
"label.tagged": "Tagged",
|
||||
"label.tags": "Tags",
|
||||
"label.tag.type": "Tag Type",
|
||||
"label.tagtypeuuid": "Tag Type",
|
||||
"label.taguuid": "Tag",
|
||||
"label.taken": "Taken",
|
||||
"label.target.iqn": "Target IQN",
|
||||
"label.tariffactions": "Actions",
|
||||
@ -1780,6 +1903,7 @@
|
||||
"label.templatesubject": "Subject",
|
||||
"label.templatetype": "Template type",
|
||||
"label.templateversion": "Template version",
|
||||
"label.term.type": "Term type",
|
||||
"label.tftpdir": "TFTP root directory",
|
||||
"label.theme.alert": "The setting is only visible to the current browser. To apply the setting, please download the JSON file and replace its content in the `theme` section of the `config.json` file under the path: `/public/config.json`",
|
||||
"label.theme.color": "Theme color",
|
||||
@ -1818,6 +1942,32 @@
|
||||
"label.transportzoneuuid": "Transport zone UUID",
|
||||
"label.try.again": "Try again",
|
||||
"label.tuesday": "Tuesday",
|
||||
"label.tungsten.fabric": "Tungsten Fabric",
|
||||
"label.tungsten.fabric.provider": "Tungsten Fabric Provider",
|
||||
"label.tungsten.fabric.routing": "Tungsten Fabric Routing",
|
||||
"label.tungsten.interface.router.table": "Interface route table",
|
||||
"label.tungsten.logical.router": "Logical Router",
|
||||
"label.tungsten.network.router.table": "Network route table",
|
||||
"label.tungsten.provider": "Tungsten provider",
|
||||
"label.tungsten.provider.gateway": "Tungsten provider gateway",
|
||||
"label.tungsten.provider.hostname": "Tungsten provider hostname",
|
||||
"label.tungsten.provider.introspectport": "Tungsten provider introspect port",
|
||||
"label.tungsten.provider.name": "Tungsten provider name",
|
||||
"label.tungsten.provider.port": "Tungsten provider port",
|
||||
"label.tungsten.provider.vrouterport": "Tungsten provider vrouter port",
|
||||
"label.tungsten.router.table": "Router Table",
|
||||
"label.tungsten.routing.polices": "Routing policies",
|
||||
"label.tungsten.static.routes": "Static Routes",
|
||||
"label.tungstengateway": "Gateway",
|
||||
"label.tungsteninterfaceroutetablename": "Name",
|
||||
"label.tungstennetworkroutetablename": "Name",
|
||||
"label.tungstenproviderhostname": "Provider hostname",
|
||||
"label.tungstenproviderintrospectport": "Provider introspect port",
|
||||
"label.tungstenproviderport": "Provider port",
|
||||
"label.tungstenprovideruuid": "Provider Uuid",
|
||||
"label.tungstenprovidervrouterport": "Provider vrouter port",
|
||||
"label.tungstenroutingpolicyterm": "Network",
|
||||
"label.tungstenvms": "VMs",
|
||||
"label.type": "Type",
|
||||
"label.type.id": "Type ID",
|
||||
"label.ucs": "UCS",
|
||||
@ -2011,9 +2161,16 @@
|
||||
"message.action.delete.backup.offering": "Please confirm that you want to delete this backup offering?",
|
||||
"message.action.delete.cluster": "Please confirm that you want to delete this cluster.",
|
||||
"message.action.delete.disk.offering": "Please confirm that you want to delete this disk offering.",
|
||||
"message.action.delete.domain": "Please confirm that you want to delete this domain.",
|
||||
"message.action.delete.external.firewall": "Please confirm that you would like to remove this external firewall. Warning: If you are planning to add back the same external firewall, you must reset usage data on the device.",
|
||||
"message.action.delete.external.load.balancer": "Please confirm that you would like to remove this external load balancer. Warning: If you are planning to add back the same external load balancer, you must reset usage data on the device.",
|
||||
"message.action.delete.ingress.rule": "Please confirm that you want to delete this ingress rule.",
|
||||
"message.action.delete.instance.group": "Please confirm that you want to delete the instance group.",
|
||||
"message.action.delete.interface.static.route": "Please confirm that you want to remove this interface Static Route?",
|
||||
"message.action.delete.iso": "Please confirm that you want to delete this ISO.",
|
||||
"message.action.delete.network": "Please confirm that you want to delete this network.",
|
||||
"message.action.delete.network.static.route": "Please confirm that you want to remove this network Static Route",
|
||||
"message.action.delete.nexusvswitch": "Please confirm that you want to delete this nexus 1000v",
|
||||
"message.action.delete.node": "Please confirm that you want to delete this node.",
|
||||
"message.action.delete.physical.network": "Please confirm that you want to delete this physical network.",
|
||||
"message.action.delete.pod": "Please confirm that you want to delete this pod.",
|
||||
@ -2023,6 +2180,7 @@
|
||||
"message.action.delete.snapshot": "Please confirm that you want to delete this snapshot.",
|
||||
"message.action.delete.system.service.offering": "Please confirm that you want to delete this system service offering.",
|
||||
"message.action.delete.template": "Please confirm that you want to delete this template.",
|
||||
"message.action.delete.tungsten.router.table": "Please confirm that you want to remove Route Table from this network?",
|
||||
"message.action.delete.volume": "Please confirm that you want to delete this volume.",
|
||||
"message.action.delete.vpn.user": "Please confirm that you want to delete the VPN user.",
|
||||
"message.action.delete.zone": "Please confirm that you want to delete this zone.",
|
||||
@ -2054,6 +2212,9 @@
|
||||
"message.action.reboot.systemvm": "Please confirm that you want to reboot this system VM.",
|
||||
"message.action.recover.volume": "Please confirm that you would like to recover this volume.",
|
||||
"message.action.release.ip": "Please confirm that you want to release this IP.",
|
||||
"message.action.remove.host": "Please confirm that you want to remove this host.",
|
||||
"message.action.remove.logical.router": "Please confirm that you want to remove Logical Router?",
|
||||
"message.action.remove.routing.policy": "Please confirm that you want to remove Routing Policy from this network",
|
||||
"message.action.release.reserved.ip": "Please confirm that you want to release this reserved IP.",
|
||||
"message.action.reserve.ip": "Please confirm that you want to reserve this IP.",
|
||||
"message.action.revert.snapshot": "Please confirm that you want to revert the owning volume to this snapshot.",
|
||||
@ -2080,8 +2241,9 @@
|
||||
"message.add.egress.rule.processing": "Adding new egress rule...",
|
||||
"message.add.failed": "Adding failed.",
|
||||
"message.add.firewall": "Add a firewall to zone",
|
||||
"message.add.firewall.rule.failed": "Adding new firewall rule failed.",
|
||||
"message.add.firewall.rule.processing": "Adding new firewall rule...",
|
||||
"message.add.firewall.rule.failed": "Adding new Firewall rule failed",
|
||||
"message.add.firewall.rule.processing": "Adding new Firewall rule...",
|
||||
"message.add.firewallrule.failed": "Adding Firewall Rule failed",
|
||||
"message.add.host": "Please specify the following parameters to add a new host.",
|
||||
"message.add.host.sshkey": "WARNING: In order to add a host with SSH key, you must ensure your hypervisor host has been configured correctly.",
|
||||
"message.add.iprange.processing": "Adding IP Range...",
|
||||
@ -2114,23 +2276,27 @@
|
||||
"message.add.tag.failed": "Failed to add new tag.",
|
||||
"message.add.tag.for.networkacl": "Add tag for NetworkACL",
|
||||
"message.add.tag.processing": "Adding new tag...",
|
||||
"message.add.template": "Please enter the following data to create your new template",
|
||||
"message.add.tungsten.routing.policy.available": "The Tungsten-Fabric routing policy is ready to launch. Please proceed to the next step.",
|
||||
"message.add.user.to.project": "This form is to enable adding specific users of an account to a project.<br>Furthermore, a ProjectRole may be added to the added user/account to allow/disallow API access at project level.<br> We can also specify the role with which the user should be added to a project - Admin/Regular; if not specified, it defaults to 'Regular'.",
|
||||
"message.add.volume": "Please fill in the following data to add a new volume.",
|
||||
"message.add.vpn.connection.failed": "Adding VPN connection failed",
|
||||
"message.add.vpn.connection.processing": "Adding VPN connection...",
|
||||
"message.add.vpn.connection.processing": "Adding VPN Connection...",
|
||||
"message.add.vpn.customer.gateway": "Adding VPN customer gateway",
|
||||
"message.add.vpn.customer.gateway.processing": "Creation of VPN customer gateway is in progress",
|
||||
"message.add.vpn.gateway": "Please confirm that you want to add a VPN Gateway.",
|
||||
"message.add.vpn.gateway.failed": "Adding VPN gateway failed",
|
||||
"message.add.vpn.gateway.processing": "Adding VPN gateway...",
|
||||
"message.added.vpc.offering": "Added VPC offering",
|
||||
"message.adding.firewall.policy": "Adding Firewall Policy",
|
||||
"message.adding.host": "Adding host",
|
||||
"message.adding.netscaler.device": "Adding Netscaler device",
|
||||
"message.adding.netscaler.provider": "Adding Netscaler provider",
|
||||
"message.advanced.security.group": "Choose this if you wish to use security groups to provide guest VM isolation.",
|
||||
"message.alert.show.all.stats.data": "It can return a lot of data depending on the settings for collecting and retaining stats.",
|
||||
"message.allowed": "Allowed",
|
||||
"message.apply.success": "Applied successfully.",
|
||||
"message.assign.instance.another": "Please specify the account type, domain, account name and network (optional) of the new account. <br> If the default NIC of the VM is on a shared network, CloudStack will check if the network can be used by the new account if you do not specify one network. <br> If the default NIC of the VM is on a isolated network, and the new account has more one isolated networks, you should specify one.",
|
||||
"message.assign.vm.failed": "Failed to assign VM.",
|
||||
"message.apply.success": "Apply Successfully",
|
||||
"message.assign.instance.another": "Please specify the account type, domain, account name and network (optional) of the new account. <br> If the default nic of the vm is on a shared network, CloudStack will check if the network can be used by the new account if you do not specify one network. <br> If the default nic of the vm is on a isolated network, and the new account has more one isolated networks, you should specify one.",
|
||||
"message.assign.vm.failed": "Failed to assign VM",
|
||||
"message.assign.vm.processing": "Assigning VM...",
|
||||
"message.attach.volume": "Please fill in the following data to attach a new volume. If you are attaching a disk volume to a Windows based virtual machine, you will need to reboot the instance to see the attached disk.",
|
||||
"message.attach.volume.failed": "Failed to attach volume.",
|
||||
@ -2146,13 +2312,13 @@
|
||||
"message.backup.restore": "Please confirm that you want to restore the vm backup?",
|
||||
"message.certificate.upload.processing": "Certificate upload in progress",
|
||||
"message.change.offering.confirm": "Please confirm that you wish to change the service offering of this virtual instance.",
|
||||
"message.confirm.change.offering.for.volume": "Please confirm that you want to change disk offering for the volume",
|
||||
"message.change.offering.for.volume": "Successfully changed offering for the volume",
|
||||
"message.change.offering.for.volume.failed": "Change offering for the volume failed",
|
||||
"message.change.offering.for.volume.processing": "Changing offering for the volume...",
|
||||
"message.change.offering.for.volume": "Successfully changed offering for the volume",
|
||||
"message.change.password": "Please change your password.",
|
||||
"message.cluster.dedicated": "Cluster dedicated",
|
||||
"message.cluster.dedicated": "Cluster Dedicated",
|
||||
"message.cluster.dedication.released": "Cluster dedication released.",
|
||||
"message.config.health.monitor.failed": "Configure Health Monitor failed",
|
||||
"message.config.sticky.policy.failed": "Failed to configure sticky policy.",
|
||||
"message.config.sticky.policy.processing": "Updating sticky policy...",
|
||||
"message.configuring.guest.traffic": "Configuring guest traffic",
|
||||
@ -2160,9 +2326,12 @@
|
||||
"message.configuring.public.traffic": "Configuring public traffic",
|
||||
"message.configuring.storage.traffic": "Configuring storage traffic",
|
||||
"message.confirm.action.force.reconnect": "Please confirm that you want to force reconnect this host.",
|
||||
"message.confirm.archive.selected.alerts": "Please confirm you would like to archive the selected alerts.",
|
||||
"message.confirm.archive.selected.events": "Please confirm you would like to archive the selected events.",
|
||||
"message.confirm.add.router.table.to.instance": "Please confirm that you want to add Route Table to this nic",
|
||||
"message.confirm.add.routing.policy": "Please confirm that you want to add Routing Policy to this network",
|
||||
"message.confirm.archive.selected.alerts": "Please confirm you would like to archive the selected alerts",
|
||||
"message.confirm.archive.selected.events": "Please confirm you would like to archive the selected events",
|
||||
"message.confirm.attach.disk": "Are you sure you want to attach disk?",
|
||||
"message.confirm.change.offering.for.volume": "Please confirm that you want to change disk offering for the volume",
|
||||
"message.confirm.configure.ovs": "Are you sure you want to configure Ovs?",
|
||||
"message.confirm.delete.acl.list": "Are you sure you want to delete this ACL list?",
|
||||
"message.confirm.delete.bigswitchbcf": "Please confirm that you would like to delete this BigSwitch BCF Controller.",
|
||||
@ -2189,8 +2358,11 @@
|
||||
"message.confirm.enable.provider": "Please confirm that you would like to enable this provider.",
|
||||
"message.confirm.enable.storage": "Please confirm that you want to enable the storage pool.",
|
||||
"message.confirm.enable.vpc.offering": "Are you sure you want to enable this VPC offering?",
|
||||
"message.confirm.remove.firewall.rule": "Please confirm that you want to delete this Firewall Rule?",
|
||||
"message.confirm.remove.ip.range": "Please confirm that you would like to remove this IP range.",
|
||||
"message.confirm.remove.network.offering": "Are you sure you want to remove this network offering?",
|
||||
"message.confirm.remove.network.policy": "Please confirm that you want to remove this Network Policy?",
|
||||
"message.confirm.remove.routing.policy": "Please confirm that you want to delete this Routing Policy?",
|
||||
"message.confirm.remove.selected.alerts": "Please confirm you would like to remove the selected alerts.",
|
||||
"message.confirm.remove.selected.events": "Please confirm you would like to remove the selected events.",
|
||||
"message.confirm.remove.vmware.datacenter": "Please confirm you want to remove VMware datacenter.",
|
||||
@ -2204,6 +2376,7 @@
|
||||
"message.confirm.upgrade.router.newer.template": "Please confirm that you want to upgrade router to use newer template.",
|
||||
"message.cpu.usage.info": "The CPU usage percentage can exceed 100% if the VM has more than 1 vCPU or when CPU Cap is not enabled. This behavior happens according to the hypervisor being used (e.g: in KVM), due to how they account the stats",
|
||||
"message.create.compute.offering": "Compute offering created",
|
||||
"message.create.tungsten.public.network": "Create Tungsten-Fabric public network",
|
||||
"message.create.internallb": "Creating internal LB",
|
||||
"message.create.internallb.failed": "Failed to create internal LB.",
|
||||
"message.create.internallb.processing": "Creation of internal LB is in progress",
|
||||
@ -2254,11 +2427,14 @@
|
||||
"message.delete.tag.failed": "Failed to delete tag",
|
||||
"message.delete.tag.for.networkacl": "Remove tag for NetworkACL",
|
||||
"message.delete.tag.processing": "Deleting tag...",
|
||||
"message.delete.tungsten.policy.rule": "Please confirm that you want to delete Policy Rule?",
|
||||
"message.delete.tungsten.tag": "Are you sure you want to remove this Tag from this Policy?",
|
||||
"message.delete.user": "Please confirm that you would like to delete this user.",
|
||||
"message.delete.vpn.connection": "Please confirm that you want to delete VPN connection.",
|
||||
"message.delete.vpn.customer.gateway": "Please confirm that you want to delete this VPN customer gateway.",
|
||||
"message.delete.vpn.gateway": "Please confirm that you want to delete this VPN Gateway.",
|
||||
"message.deleting.node": "Deleting node",
|
||||
"message.deleting.firewall.policy": "Deleting Firewall Policy",
|
||||
"message.deleting.node": "Deleting Node",
|
||||
"message.deleting.vm": "Deleting VM",
|
||||
"message.denied": "Denied",
|
||||
"message.deployasis": "Selected template is Deploy As-Is i.e., the VM is deployed by importing an OVA with vApps directly into vCenter. Root disk(s) resize is allowed only on stopped VMs for such templates.",
|
||||
@ -2313,9 +2489,17 @@
|
||||
"message.enter.valid.nic.ip": "Please enter a valid IP address for NIC",
|
||||
"message.error.access.key": "Please enter access key.",
|
||||
"message.error.add.guest.network": "Either IPv4 fields or IPv6 fields need to be filled when adding a guest network.",
|
||||
"message.error.add.interface.static.route": "Adding interface Static Route failed",
|
||||
"message.error.add.logical.router": "Adding Logical Router failed",
|
||||
"message.error.add.network.static.route": "Adding network Static Route failed",
|
||||
"message.error.add.policy.rule": "Adding Policy rule failed",
|
||||
"message.error.add.secondary.ipaddress": "There was an error adding the secondary IP Address.",
|
||||
"message.error.add.tungsten.router.table": "Adding Router Table failed",
|
||||
"message.error.add.tungsten.routing.policy": "Adding Tungsten-Fabric Routing Policy failed",
|
||||
"message.error.agent.password": "Please enter agent password.",
|
||||
"message.error.agent.username": "Please enter agent username.",
|
||||
"message.error.apply.network.policy": "Applying Network Policy failed",
|
||||
"message.error.apply.tungsten.tag": "Applying Tag failed",
|
||||
"message.error.binaries.iso.url": "Please enter binaries ISO URL.",
|
||||
"message.error.bucket": "Please enter bucket",
|
||||
"message.error.cloudian.console": "Single-Sign-On failed for Cloudian management console. Please ask your administrator to fix integration issues.",
|
||||
@ -2325,12 +2509,16 @@
|
||||
"message.error.current.password": "Please enter current password.",
|
||||
"message.error.custom.disk.size": "Please enter custom disk size.",
|
||||
"message.error.date": "Please select a date.",
|
||||
"message.error.delete.interface.static.route": "Removing interface Static Route failed",
|
||||
"message.error.delete.network.static.route": "Removing network Static Route failed",
|
||||
"message.error.delete.tungsten.policy.rule": "Deleting Policy rule failed",
|
||||
"message.error.delete.tungsten.router.table": "Removing Router Table failed",
|
||||
"message.error.delete.tungsten.tag": "Removing Tag failed",
|
||||
"message.error.description": "Please enter description.",
|
||||
"message.error.discovering.feature": "Exception caught while discovering features.",
|
||||
"message.error.display.text": "Please enter display text.",
|
||||
"message.error.duration.less.than.interval": "The duration in Autoscale policy cannot be less than interval",
|
||||
"message.error.enable.saml": "Unable to find users IDs to enable SAML single sign on, kindly enable it manually.",
|
||||
"message.error.end.date.and.time": "Please select the end date and time!",
|
||||
"message.error.endip": "Please enter end IP.",
|
||||
"message.error.gateway": "Please enter gateway.",
|
||||
"message.error.host.name": "Please enter host name.",
|
||||
@ -2346,7 +2534,7 @@
|
||||
"message.error.invalid.autoscale.vmgroup.name": "Invalid AutoScale VM group name. It can contain the ASCII letters 'a' through 'z', 'A' through 'Z', the digits '0' through '9' and the hyphen ('-'), must be between 1 and 255 characters long.",
|
||||
"message.error.ip.range": "Please enter valid range.",
|
||||
"message.error.ipv4.address": "Please enter a valid IPv4 address.",
|
||||
"message.error.ipv4.dns1": "Please enter IpV4 DNS 1.",
|
||||
"message.error.ipv4.dns2": "Please enter IpV4 DNS 2",
|
||||
"message.error.ipv6.address": "Please enter a valid IP v6 address.",
|
||||
"message.error.ipv6.gateway": "Please enter IpV6 Gateway",
|
||||
"message.error.ipv6.gateway.format": "Please enter a valid IPv6 Gateway.",
|
||||
@ -2375,11 +2563,15 @@
|
||||
"message.error.rados.pool": "Please enter RADOS pool",
|
||||
"message.error.rados.secret": "Please enter RADOS secret",
|
||||
"message.error.rados.user": "Please enter RADOS user",
|
||||
"message.error.remove.logical.router": "Removing Logical Router failed",
|
||||
"message.error.remove.network.policy": "Removing Network Policy failed",
|
||||
"message.error.remove.nic": "There was an error",
|
||||
"message.error.remove.secondary.ipaddress": "There was an error removing the secondary IP Address",
|
||||
"message.error.reset.config": "Unable to reset config to default value",
|
||||
"message.error.remove.tungsten.routing.policy": "Removing Tungsten-Fabric Routing Policy from network failed",
|
||||
"message.error.required.input": "Please enter input",
|
||||
"message.error.reset.config": "Unable to reset config to default value",
|
||||
"message.error.retrieve.kubeconfig": "Unable to retrieve Kubernetes cluster config",
|
||||
"message.error.routing.policy.term": "Community need to have the following format number:number",
|
||||
"message.error.s3nfs.path": "Please enter S3 NFS Path",
|
||||
"message.error.s3nfs.server": "Please enter S3 NFS Server",
|
||||
"message.error.select.load.balancer": "Please select a load balancer",
|
||||
@ -2450,13 +2642,14 @@
|
||||
"message.host.dedicated": "Host Dedicated",
|
||||
"message.host.dedication.released": "Host dedication released.",
|
||||
"message.info.cloudian.console": "Cloudian Management Console should open in another window.",
|
||||
"message.installwizard.cloudstack.helptext.header": "\nYou can find more information about Apache CloudStack™ on the pages listed below.\n",
|
||||
"message.installwizard.cloudstack.helptext.website": " * Project website:\t ",
|
||||
"message.infra.setup.tungsten.description": "This zone must contain a Tungsten-Fabric provider because the isolation method is TF",
|
||||
"message.installwizard.cloudstack.helptext.document": " * Documentation:\t ",
|
||||
"message.installwizard.cloudstack.helptext.releasenotes": " * Release notes:\t ",
|
||||
"message.installwizard.cloudstack.helptext.mailinglists": " * Join mailing lists:\t ",
|
||||
"message.installwizard.cloudstack.helptext.survey": " * Take the survey:\t ",
|
||||
"message.installwizard.cloudstack.helptext.header": "\nYou can find more information about Apache CloudStack™ on the pages listed below.\n",
|
||||
"message.installwizard.cloudstack.helptext.issues": " * Report issues:\t ",
|
||||
"message.installwizard.cloudstack.helptext.mailinglists": " * Join mailing lists:\t ",
|
||||
"message.installwizard.cloudstack.helptext.releasenotes": " * Release notes:\t ",
|
||||
"message.installwizard.cloudstack.helptext.survey": " * Take the survey:\t ",
|
||||
"message.installwizard.copy.whatiscloudstack": "CloudStack™ is a software platform that pools computing resources to build public, private, and hybrid Infrastructure as a Service (IaaS) clouds. CloudStack™ manages the network, storage, and compute nodes that make up a cloud infrastructure. Use CloudStack™ to deploy, manage, and configure cloud computing environments.\n\nExtending beyond individual virtual machine images running on commodity hardware, CloudStack™ provides a turnkey cloud infrastructure software stack for delivering virtual datacenters as a service - delivering all of the essential components to build, deploy, and manage multi-tier and multi-tenant cloud applications. Both open-source and Premium versions are available, with the open-source version offering nearly identical features.",
|
||||
"message.installwizard.tooltip.addpod.name": "A name for the pod.",
|
||||
"message.installwizard.tooltip.addpod.reservedsystemendip": "This is the IP range in the private network that the CloudStack uses to manage Secondary Storage VMs and Console Proxy VMs. These IP addresses are taken from the same subnet as computing servers.",
|
||||
@ -2466,6 +2659,12 @@
|
||||
"message.installwizard.tooltip.configureguesttraffic.guestgateway": "The gateway that the guests should use.",
|
||||
"message.installwizard.tooltip.configureguesttraffic.guestnetmask": "The netmask in use on the subnet that the guests should use.",
|
||||
"message.installwizard.tooltip.configureguesttraffic.gueststartip": "The range of IP addresses that will be available for allocation to guests in this zone. If one NIC is used, these IPs should be in the same CIDR as the pod CIDR.",
|
||||
"message.installwizard.tooltip.tungsten.provider.gateway": "Tungsten provider gateway is required",
|
||||
"message.installwizard.tooltip.tungsten.provider.hostname": "Tungsten provider hostname is required",
|
||||
"message.installwizard.tooltip.tungsten.provider.introspectport": "Tungsten provider introspect port is required",
|
||||
"message.installwizard.tooltip.tungsten.provider.name": "Tungsten provider name is required",
|
||||
"message.installwizard.tooltip.tungsten.provider.port": "Tungsten provider port is required",
|
||||
"message.installwizard.tooltip.tungsten.provider.vrouterport": "Tungsten provider vrouter port is required",
|
||||
"message.instances.managed": "Instances or VMs controlled by CloudStack.",
|
||||
"message.instances.unmanaged": "Instances or VMs not controlled by CloudStack.",
|
||||
"message.interloadbalance.not.return.elementid": "error: listInternalLoadBalancerElements API doesn't return internal LB element ID.",
|
||||
@ -2483,8 +2682,19 @@
|
||||
"message.launch.zone.description": "Zone is ready to launch; please proceed to the next step.",
|
||||
"message.launch.zone.hint": "Configure network components and traffic including IP addresses.",
|
||||
"message.license.agreements.not.accepted": "License agreements not accepted.",
|
||||
"message.linstor.resourcegroup.description": "Linstor resource group to use for primary storage.",
|
||||
"message.listnsp.not.return.providerid": "error: listNetworkServiceProviders API doesn't return VirtualRouter provider ID.",
|
||||
"message.load.host.failed": "Failed to load hosts.",
|
||||
"message.loading.add.interface.static.route": "Adding interface Static Route...",
|
||||
"message.loading.add.network.static.route": "Adding network Static Route...",
|
||||
"message.loading.add.policy.rule": "Adding Policy rule...",
|
||||
"message.loading.add.tungsten.router.table": "Adding Router Table...",
|
||||
"message.loading.apply.tungsten.tag": "Applying Tag...",
|
||||
"message.loading.delete.interface.static.route": "Removing interface Static Route...",
|
||||
"message.loading.delete.network.static.route": "Removing network Static Route...",
|
||||
"message.loading.delete.tungsten.policy.rule": "Deleting Policy rule...",
|
||||
"message.loading.delete.tungsten.router.table": "Removing Router Table...",
|
||||
"message.loading.delete.tungsten.tag": "Removing Tag...",
|
||||
"message.lock.account": "Please confirm that you want to lock this account. By locking the account, all users for this account will no longer be able to manage their cloud resources. Existing resources can still be accessed.",
|
||||
"message.login.failed": "Login Failed",
|
||||
"message.migrate.instance.host.auto.assign": "Host for the instance will be automatically chosen based on the suitability within the same cluster",
|
||||
@ -2561,6 +2771,8 @@
|
||||
"message.remove.ldap": "Are you sure you want to delete the LDAP configuration?",
|
||||
"message.remove.nic.processing": "Removing NIC...",
|
||||
"message.remove.port.forward.failed": "Removing port forwarding rule failed",
|
||||
"message.remove.router.table.from.interface": "Please confirm that you want to remove Route Table from this nic",
|
||||
"message.remove.router.table.from.interface.failed": "Removing Router Table from interface failed",
|
||||
"message.remove.rule.failed": "Failed to delete rule",
|
||||
"message.remove.secondary.ipaddress.processing": "Removing secondary IP address...",
|
||||
"message.remove.securitygroup.rule.processing": "Deleting security-group rule...",
|
||||
@ -2571,7 +2783,6 @@
|
||||
"message.required.add.least.ip": "Please add at least 1 IP Range",
|
||||
"message.required.traffic.type": "Error in configuration! All required traffic types should be added and with multiple physical networks each network should have a label.",
|
||||
"message.reset.vpn.connection": "Please confirm that you want to reset VPN connection.",
|
||||
"message.linstor.resourcegroup.description": "Linstor resource group to use for primary storage.",
|
||||
"message.resize.volume.failed": "Failed to resize volume.",
|
||||
"message.resize.volume.processing": "Volume resize is in progress",
|
||||
"message.resource.not.found": "Resource not found.",
|
||||
@ -2619,28 +2830,39 @@
|
||||
"message.success.add.egress.rule": "Successfully added new egress rule",
|
||||
"message.success.add.firewall.rule": "Successfully added new firewall rule",
|
||||
"message.success.add.guest.network": "Successfully created guest network",
|
||||
"message.success.add.interface.static.route": "Successfully added interface Static Route",
|
||||
"message.success.add.iprange": "Successfully added IP range",
|
||||
"message.success.add.ip.v6.prefix": "Successfully added IPv6 Prefix",
|
||||
"message.success.add.kuberversion": "Successfully added Kubernetes version",
|
||||
"message.success.add.logical.router": "Successfully added Logical Router",
|
||||
"message.success.add.network": "Successfully added network",
|
||||
"message.success.add.network.acl": "Successfully added Network ACL list",
|
||||
"message.success.add.network.static.route": "Successfully added network Static Route",
|
||||
"message.success.add.network.permissions": "Successfully added network permissions",
|
||||
"message.success.add.policy.rule": "Successfully added Policy rule",
|
||||
"message.success.add.port.forward": "Successfully added new port forwarding rule",
|
||||
"message.success.add.private.gateway": "Successfully added private gateway",
|
||||
"message.success.add.router.table.to.instance": "Successfully added Router Table to instance",
|
||||
"message.success.add.rule": "Successfully added new rule",
|
||||
"message.success.add.secondary.ipaddress": "Successfully added secondary IP address",
|
||||
"message.success.add.static.route": "Successfully added static route",
|
||||
"message.success.add.tag": "Successfully added new tag",
|
||||
"message.success.add.tungsten.router.table": "Successfully added Router Table",
|
||||
"message.success.add.tungsten.routing.policy": "Successfully added Tungsten-Fabric routing policy",
|
||||
"message.success.add.vpc.network": "Successfully added VPC network",
|
||||
"message.success.add.vpn.customer.gateway": "Successfully added VPN customer gateway",
|
||||
"message.success.add.vpn.gateway": "Successfully added VPN gateway",
|
||||
"message.success.assign.vm": "Successfully assigned VM",
|
||||
"message.success.apply.network.policy": "Successfully applied Network Policy",
|
||||
"message.success.apply.tungsten.tag": "Successfully applied Tag",
|
||||
"message.success.asign.vm": "Successfully assigned VM",
|
||||
"message.success.assigned.vms": "Successfully assigned VMs",
|
||||
"message.success.certificate.upload": "Certificate successfully uploaded",
|
||||
"message.success.change.affinity.group": "Successfully changed affinity groups",
|
||||
"message.success.change.offering": "Successfully changed offering",
|
||||
"message.success.change.password": "Successfully changed password for user",
|
||||
"message.success.config.backup.schedule": "Successfully configured VM backup schedule",
|
||||
"message.success.config.health.monitor": "Successfully Configure Health Monitor",
|
||||
"message.success.config.sticky.policy": "Successfully configured sticky policy",
|
||||
"message.success.copy.clipboard": "Successfully copied to clipboard",
|
||||
"message.success.create.account": "Successfully created account",
|
||||
@ -2656,10 +2878,15 @@
|
||||
"message.success.delete.acl.rule": "Successfully removed ACL rule",
|
||||
"message.success.delete.backup.schedule": "Successfully deleted configure VM backup schedule",
|
||||
"message.success.delete.icon": "Successfully deleted icon of",
|
||||
"message.success.delete.interface.static.route": "Successfully removed interface Static Route",
|
||||
"message.success.delete.network.static.route": "Successfully removed network Static Route",
|
||||
"message.success.delete.node": "Successfully deleted node",
|
||||
"message.success.delete.snapshot.policy": "Successfully deleted snapshot policy",
|
||||
"message.success.delete.static.route": "Successfully deleted static route",
|
||||
"message.success.delete.tag": "Successfully deleted tag",
|
||||
"message.success.delete.tungsten.policy.rule": "Successfully deledted Policy rule",
|
||||
"message.success.delete.tungsten.router.table": "Successfully removed Router Table",
|
||||
"message.success.delete.tungsten.tag": "Successfully removed Tag",
|
||||
"message.success.delete.vm": "Successfully deleted VM",
|
||||
"message.success.disable.saml.auth": "Successfully disabled SAML authorization",
|
||||
"message.success.disable.vpn": "Successfully disabled VPN",
|
||||
@ -2681,12 +2908,16 @@
|
||||
"message.success.remove.instance.rule": "Successfully removed instance from rule",
|
||||
"message.success.remove.ip": "Successfully removed IP",
|
||||
"message.success.remove.iprange": "Successfully removed IP Range",
|
||||
"message.success.remove.network.permissions": "Successfully removed network permissions",
|
||||
"message.success.remove.logical.router": "Successfully removed Logical Router",
|
||||
"message.success.remove.network.policy": "Successfully removed Network Policy",
|
||||
"message.success.remove.network.permissions": "Successfully removed Network Permissions",
|
||||
"message.success.remove.nic": "Successfully removed",
|
||||
"message.success.remove.port.forward": "Successfully removed port forwarding rule",
|
||||
"message.success.remove.router.table.from.interface": "Successfully removed Route Table from interface",
|
||||
"message.success.remove.rule": "Successfully deleted rule",
|
||||
"message.success.remove.secondary.ipaddress": "Successfully removed secondary IP address",
|
||||
"message.success.remove.sticky.policy": "Successfully removed sticky policy",
|
||||
"message.success.remove.tungsten.routing.policy": "Successfully removed Tungsten-Fabric Routing Policy from network",
|
||||
"message.success.reset.network.permissions": "Successfully reset Network Permissions",
|
||||
"message.success.resize.volume": "Successfully resized volume",
|
||||
"message.success.scale.kubernetes": "Successfully scaled Kubernetes cluster",
|
||||
|
||||
26
ui/src/assets/icons/tungsten.svg
Normal file
26
ui/src/assets/icons/tungsten.svg
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.16, written by Peter Selinger 2001-2019
|
||||
</metadata>
|
||||
<g class="custom-icon" transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M780 1788 c-12 -46 -32 -118 -43 -160 l-22 -78 -117 0 -117 0 -10
|
||||
-37 c-6 -21 -22 -76 -35 -122 -14 -47 -23 -88 -20 -93 3 -4 54 -8 115 -8 60 0
|
||||
109 -4 109 -9 0 -5 -18 -76 -39 -157 -169 -636 -175 -658 -219 -697 -29 -27
|
||||
-93 -33 -133 -13 l-32 16 -100 -99 c-69 -67 -98 -103 -94 -114 10 -26 91 -67
|
||||
154 -78 165 -29 373 84 466 253 l32 58 173 0 c94 0 172 -2 172 -5 0 -3 -18
|
||||
-70 -40 -150 -22 -80 -40 -150 -40 -155 0 -7 46 -10 132 -8 l133 3 31 115 c17
|
||||
63 36 134 43 158 l12 42 115 0 114 0 11 27 c16 43 59 206 59 226 0 15 -12 17
|
||||
-110 17 -93 0 -110 2 -110 16 0 8 18 83 41 167 22 84 58 217 79 297 87 327 96
|
||||
352 144 381 36 22 76 24 123 7 l34 -12 101 101 c99 99 101 103 84 121 -9 11
|
||||
-44 32 -78 47 -55 25 -69 27 -147 23 -157 -8 -293 -94 -387 -244 l-46 -74
|
||||
-169 0 c-93 0 -169 4 -169 8 0 4 18 73 39 152 22 80 37 148 34 152 -2 5 -60 8
|
||||
-127 8 l-124 0 -22 -82z m460 -509 c0 -11 -61 -246 -118 -454 l-27 -100 -168
|
||||
-3 c-92 -1 -167 1 -167 6 0 14 130 505 145 550 6 16 335 18 335 1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -32,7 +32,7 @@
|
||||
<a-menu>
|
||||
<a-menu-item v-for="(column, idx) in columnKeys" :key="idx" @click="updateSelectedColumns(column)">
|
||||
<a-checkbox :id="idx.toString()" :checked="selectedColumns.includes(getColumnKey(column))"/>
|
||||
{{ $t('label.' + String(getColumnKey(column)).toLowerCase()) }}
|
||||
{{ $t('label.' + String(getColumTitle(column)).toLowerCase()) }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
@ -110,6 +110,15 @@
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ $t(text.toLowerCase()) }}</router-link>
|
||||
<router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
|
||||
</span>
|
||||
<span v-else-if="$route.path.startsWith('/tungstenfabric')">
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ $t(text.toLowerCase()) }}</router-link>
|
||||
<router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
|
||||
</span>
|
||||
<span v-else-if="isTungstenPath()">
|
||||
<router-link :to="{ path: $route.path + '/' + record.uuid, query: { zoneid: record.zoneid } }" v-if="record.uuid && record.zoneid">{{ $t(text.toLowerCase()) }}</router-link>
|
||||
<router-link :to="{ path: $route.path + '/' + record.uuid, query: { zoneid: $route.query.zoneid } }" v-else-if="record.uuid && $route.query.zoneid">{{ $t(text.toLowerCase()) }}</router-link>
|
||||
<router-link :to="{ path: $route.path }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
|
||||
</span>
|
||||
<span v-else>
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ text }}</router-link>
|
||||
<router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ text }}</router-link>
|
||||
@ -516,6 +525,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isTungstenPath () {
|
||||
return ['/tungstennetworkroutertable', '/tungstenpolicy', '/tungsteninterfaceroutertable',
|
||||
'/tungstenpolicyset', '/tungstenroutingpolicy', '/firewallrule', '/tungstenfirewallpolicy'].includes(this.$route.path)
|
||||
},
|
||||
createPathBasedOnVmType: createPathBasedOnVmType,
|
||||
quickViewEnabled () {
|
||||
return new RegExp(['/vm', '/kubernetes', '/ssh', '/userdata', '/vmgroup', '/affinitygroup', '/autoscalevmgroup',
|
||||
@ -524,7 +537,8 @@ export default {
|
||||
'/template', '/iso',
|
||||
'/project', '/account',
|
||||
'/zone', '/pod', '/cluster', '/host', '/storagepool', '/imagestore', '/systemvm', '/router', '/ilbvm', '/annotation',
|
||||
'/computeoffering', '/systemoffering', '/diskoffering', '/backupoffering', '/networkoffering', '/vpcoffering'].join('|'))
|
||||
'/computeoffering', '/systemoffering', '/diskoffering', '/backupoffering', '/networkoffering', '/vpcoffering',
|
||||
'/tungstenfabric'].join('|'))
|
||||
.test(this.$route.path)
|
||||
},
|
||||
enableGroupAction () {
|
||||
@ -791,6 +805,12 @@ export default {
|
||||
return host.state
|
||||
},
|
||||
getColumnKey (name) {
|
||||
if (typeof name === 'object') {
|
||||
name = Object.keys(name).includes('field') ? name.field : name.customTitle
|
||||
}
|
||||
return name
|
||||
},
|
||||
getColumTitle (name) {
|
||||
if (typeof name === 'object') {
|
||||
name = Object.keys(name).includes('customTitle') ? name.customTitle : name.field
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
v-model:value="searchQuery"
|
||||
style="margin-bottom: 10px;"
|
||||
@search="fetchNetworks"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
<a-table
|
||||
size="small"
|
||||
style="overflow-y: auto"
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
v-model:value="searchQuery"
|
||||
style="margin-bottom: 10px;"
|
||||
@search="fetchStoragePools"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
<a-table
|
||||
size="small"
|
||||
style="overflow-y: auto"
|
||||
|
||||
@ -19,12 +19,18 @@
|
||||
<a-breadcrumb class="breadcrumb">
|
||||
<a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
|
||||
<router-link
|
||||
v-if="item && item.name"
|
||||
v-if="item && item.name && !tungstenPaths.includes(item.path)"
|
||||
:to="{ path: item.path === '' ? '/' : item.path }"
|
||||
>
|
||||
<render-icon v-if="index == 0" :icon="item.meta.icon" style="font-size: 16px" @click="resetToMainView" />
|
||||
<span v-if="item.meta.title">{{ $t(item.meta.title) }}</span>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-else-if="tungstenPaths.includes(item.path)"
|
||||
:to="{ path: item.path === '' ? '/' : item.path, query: { zoneid: $route.query.zoneid } }">
|
||||
<render-icon v-if="index == 0" :icon="item.meta.icon" style="font-size: 16px" @click="resetToMainView" />
|
||||
{{ $t(item.meta.title) }}
|
||||
</router-link>
|
||||
<span v-else-if="$route.params.id">
|
||||
<label
|
||||
v-if="'name' in resource &&
|
||||
@ -75,7 +81,9 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
name: '',
|
||||
breadList: []
|
||||
breadList: [],
|
||||
tungstenPaths: ['/tungstennetworkroutertable', '/tungstenpolicy', '/tungsteninterfaceroutertable',
|
||||
'/tungstenpolicyset', '/tungstenroutingpolicy', '/firewallrule', '/tungstenfirewallpolicy']
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
import tungsten from '@/assets/icons/tungsten.svg?inline'
|
||||
import { isAdmin } from '@/role'
|
||||
|
||||
export default {
|
||||
@ -75,6 +76,18 @@ export default {
|
||||
name: 'guest.ip.range',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/GuestIpRanges.vue'))),
|
||||
show: (record) => { return 'listVlanIpRanges' in store.getters.apis && (record.type === 'Shared' || (record.service && record.service.filter(x => x.name === 'SourceNat').count === 0)) }
|
||||
}, {
|
||||
name: 'network.policy',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/NetworkPolicyTab.vue'))),
|
||||
show: (record) => {
|
||||
return ('listTungstenFabricPolicy' in store.getters.apis) && (record.broadcasturi === 'tf://tf' && record.type !== 'Shared')
|
||||
}
|
||||
}, {
|
||||
name: 'tungsten.logical.router',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/LogicalRouterTab.vue'))),
|
||||
show: (record) => {
|
||||
return ('listTungstenFabricLogicalRouter' in store.getters.apis) && (record.broadcasturi === 'tf://tf' && record.type !== 'Shared')
|
||||
}
|
||||
}, {
|
||||
name: 'network.permissions',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/NetworkPermissions.vue'))),
|
||||
@ -747,6 +760,148 @@ export default {
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'tungstenfabric',
|
||||
title: 'label.tungsten.fabric',
|
||||
icon: shallowRef(tungsten),
|
||||
permission: ['listTungstenFabricProviders'],
|
||||
columns: [
|
||||
{
|
||||
field: 'name',
|
||||
customTitle: 'tungsten.fabric.provider'
|
||||
},
|
||||
'zonename'
|
||||
],
|
||||
details: ['name', 'tungstengateway', 'tungstenproviderhostname', 'tungstenproviderintrospectport', 'tungstenproviderport', 'tungstenprovideruuid', 'tungstenprovidervrouterport', 'zonename'],
|
||||
resourceType: 'TungstenFabric',
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'tungsten.fabric',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/TungstenFabric.vue'))),
|
||||
show: (record) => { return !record.securitygroupsenabled }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'tungstenpolicy',
|
||||
title: 'label.network.policy',
|
||||
icon: shallowRef(tungsten),
|
||||
hidden: true,
|
||||
permission: ['listTungstenFabricPolicy'],
|
||||
columns: ['name', 'zonename'],
|
||||
details: ['name', 'zonename'],
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'rule',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/TungstenFabricPolicyRule.vue')))
|
||||
},
|
||||
{
|
||||
name: 'tag',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/TungstenFabricPolicyTag.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'deleteTungstenFabricPolicy',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.policy',
|
||||
message: 'label.confirm.delete.tungsten.policy',
|
||||
dataView: true,
|
||||
mapping: {
|
||||
policyuuid: {
|
||||
value: (record) => { return record.uuid }
|
||||
},
|
||||
zoneid: {
|
||||
value: (record) => { return record.zoneid }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'tungstenpolicyset',
|
||||
title: 'label.application.policy.set',
|
||||
icon: shallowRef(tungsten),
|
||||
hidden: true,
|
||||
permission: ['listTungstenFabricApplicationPolicySet'],
|
||||
columns: ['name', 'zonename'],
|
||||
details: ['name', 'zonename'],
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'firewall.policy',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/FirewallPolicyTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'tag',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/FirewallTagTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'deleteTungstenFabricApplicationPolicySet',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.policy.set',
|
||||
message: 'label.confirm.delete.tungsten.policy.set',
|
||||
dataView: true,
|
||||
mapping: {
|
||||
applicationpolicysetuuid: {
|
||||
value: (record) => { return record.uuid }
|
||||
},
|
||||
zoneid: {
|
||||
value: (record) => { return record.zoneid }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'tungstenfirewallpolicy',
|
||||
title: 'label.firewall.policy',
|
||||
icon: shallowRef(tungsten),
|
||||
hidden: true,
|
||||
permission: ['listTungstenFabricFirewallPolicy'],
|
||||
columns: ['name', 'zonename'],
|
||||
details: ['uuid', 'name', 'zonename'],
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'firewallrule',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/tungsten/FirewallRuleTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'deleteTungstenFabricFirewallPolicy',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.firewall.policy',
|
||||
message: 'label.confirm.delete.tungsten.firewall.policy',
|
||||
dataView: true,
|
||||
mapping: {
|
||||
firewallpolicyuuid: {
|
||||
value: (record) => { return record.uuid }
|
||||
},
|
||||
zoneid: {
|
||||
value: (record) => { return record.zoneid }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'guestvlans',
|
||||
title: 'label.guest.vlan',
|
||||
|
||||
@ -157,6 +157,7 @@ import {
|
||||
UsergroupDeleteOutlined,
|
||||
UserOutlined,
|
||||
UploadOutlined,
|
||||
WarningOutlined,
|
||||
WifiOutlined,
|
||||
SolutionOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
@ -305,6 +306,7 @@ export default {
|
||||
app.component('UsergroupDeleteOutlined', UsergroupDeleteOutlined)
|
||||
app.component('UserOutlined', UserOutlined)
|
||||
app.component('UploadOutlined', UploadOutlined)
|
||||
app.component('WarningOutlined', WarningOutlined)
|
||||
app.component('WifiOutlined', WifiOutlined)
|
||||
app.component('renderIcon', renderIcon)
|
||||
app.component('SolutionOutlined', SolutionOutlined)
|
||||
|
||||
@ -132,6 +132,22 @@ a {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
.custom-icon path {
|
||||
fill: @navigation-text-color;
|
||||
}
|
||||
|
||||
.ant-menu-light {
|
||||
.ant-menu-item:hover > a,
|
||||
.ant-menu-submenu-title:hover > a,
|
||||
.ant-menu-submenu-title:hover,
|
||||
.ant-menu-item:hover,
|
||||
.ant-menu-submenu-title:hover {
|
||||
.custom-icon path {
|
||||
fill: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
|
||||
background-color: @primary-color-light;
|
||||
}
|
||||
@ -260,6 +276,7 @@ a {
|
||||
|
||||
.custom-icon path {
|
||||
color: @primary-color;
|
||||
fill: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,6 +309,7 @@ a {
|
||||
|
||||
.custom-icon path {
|
||||
color: @primary-color;
|
||||
fill: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -809,7 +809,7 @@ export default {
|
||||
let title = columnKey === 'cidr' && this.columnKeys.includes('ip6cidr') ? 'ipv4.cidr' : columnKey
|
||||
if (typeof columnKey === 'object') {
|
||||
if ('customTitle' in columnKey && 'field' in columnKey) {
|
||||
key = columnKey.customTitle
|
||||
key = columnKey.field
|
||||
title = columnKey.customTitle
|
||||
customRender[key] = columnKey[key]
|
||||
} else {
|
||||
@ -866,6 +866,21 @@ export default {
|
||||
} else if (this.$route.path.startsWith('/ldapsetting/')) {
|
||||
params.hostname = this.$route.params.id
|
||||
}
|
||||
if (this.$route.path.startsWith('/tungstenpolicy/')) {
|
||||
params.policyuuid = this.$route.params.id
|
||||
}
|
||||
if (this.$route.path.startsWith('/tungstenpolicyset/')) {
|
||||
params.applicationpolicysetuuid = this.$route.params.id
|
||||
}
|
||||
if (this.$route.path.startsWith('/tungstennetworkroutertable/')) {
|
||||
params.tungstennetworkroutetableuuid = this.$route.params.id
|
||||
}
|
||||
if (this.$route.path.startsWith('/tungsteninterfaceroutertable/')) {
|
||||
params.tungsteninterfaceroutetableuuid = this.$route.params.id
|
||||
}
|
||||
if (this.$route.path.startsWith('/tungstenfirewallpolicy/')) {
|
||||
params.firewallpolicyuuid = this.$route.params.id
|
||||
}
|
||||
}
|
||||
|
||||
if (this.$store.getters.listAllProjects && !this.projectView) {
|
||||
@ -1446,7 +1461,7 @@ export default {
|
||||
if (!action.mapping[key].value) {
|
||||
continue
|
||||
}
|
||||
params[key] = action.mapping[key].value(this.resource, params)
|
||||
params[key] = action.mapping[key].value(this.resource, params, this.$route.query)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
v-if="resource && resource.hypervisor === 'VMware'"
|
||||
ref="forced"
|
||||
name="forced">
|
||||
<a-switch v-model:checked="form.forced" :auto-focus="true" />
|
||||
<a-switch v-model:checked="form.forced" v-focus="true" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div :span="24" class="action-button">
|
||||
|
||||
@ -123,7 +123,8 @@
|
||||
:disabled="!['Created', 'Running'].includes(resource.state) || resource.autoscalingenabled"
|
||||
>
|
||||
<a-button
|
||||
type="danger"
|
||||
danger
|
||||
type="primary"
|
||||
shape="circle"
|
||||
:disabled="!['Created', 'Running'].includes(resource.state) || resource.autoscalingenabled">
|
||||
<template #icon><delete-outlined /></template>
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
:placeholder="$t('label.search')"
|
||||
v-model:value="filter"
|
||||
@search="handleSearch"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
</div>
|
||||
|
||||
<div class="form__item">
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
<a-input
|
||||
v-model:value="form.name"
|
||||
:placeholder="apiParams.name.description"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
</a-form-item>
|
||||
<a-form-item name="displaytext" ref="displaytext">
|
||||
<template #label>
|
||||
@ -40,7 +40,7 @@
|
||||
<a-input
|
||||
v-model:value="form.displaytext"
|
||||
:placeholder="apiParams.displaytext.description"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
</a-form-item>
|
||||
<a-form-item name="passwordenabled" ref="passwordenabled">
|
||||
<template #label>
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
v-focus="true"
|
||||
v-model:value="form.zoneid"
|
||||
:placeholder="placeholder.zoneid"
|
||||
autoFocus
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
|
||||
@ -1037,6 +1037,22 @@ export default {
|
||||
columns: ['name', 'state', 'hostname', 'zonename']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Tungsten',
|
||||
details: ['name', 'state', 'id', 'physicalnetworkid', 'servicelist'],
|
||||
lists: [
|
||||
{
|
||||
title: 'label.tungsten.fabric.provider',
|
||||
api: 'listTungstenFabricProviders',
|
||||
mapping: {
|
||||
zoneid: {
|
||||
value: (record) => { return record.zoneid }
|
||||
}
|
||||
},
|
||||
columns: ['name', 'tungstenproviderhostname', 'tungstenproviderport', 'tungstengateway', 'tungstenprovidervrouterport', 'tungstenproviderintrospectport']
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ export default {
|
||||
{
|
||||
name: 'network',
|
||||
title: 'label.network',
|
||||
step: ['physicalNetwork', 'netscaler', 'pod', 'guestTraffic', 'storageTraffic', 'publicTraffic'],
|
||||
step: ['physicalNetwork', 'tungsten', 'netscaler', 'pod', 'guestTraffic', 'storageTraffic', 'publicTraffic'],
|
||||
description: this.$t('message.network.description'),
|
||||
hint: this.$t('message.network.hint')
|
||||
},
|
||||
|
||||
@ -178,6 +178,14 @@ export default {
|
||||
},
|
||||
selectedBaremetalProviders () {
|
||||
return this.prefillContent?.networkOfferingSelected?.selectedBaremetalProviders || []
|
||||
},
|
||||
physicalNetworks () {
|
||||
const tungstenNetworks = this.prefillContent.physicalNetworks.filter(network => network.isolationMethod === 'TF')
|
||||
if (tungstenNetworks && tungstenNetworks.length > 0) {
|
||||
return tungstenNetworks
|
||||
}
|
||||
|
||||
return this.prefillContent.physicalNetworks
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
@ -466,6 +474,12 @@ export default {
|
||||
this.stepData.physicalNetworkReturned = physicalNetworkReturned
|
||||
this.stepData.physicalNetworkItem['createPhysicalNetwork' + index] = physicalNetworkReturned
|
||||
this.stepData.stepMove.push('createPhysicalNetwork' + index)
|
||||
|
||||
if (physicalNetwork.isolationMethod === 'TF' &&
|
||||
physicalNetwork.traffics.findIndex(traffic => traffic.type === 'public') > -1) {
|
||||
this.stepData.isTungstenZone = true
|
||||
this.stepData.tungstenPhysicalNetworkId = physicalNetworkReturned.id
|
||||
}
|
||||
} else {
|
||||
this.stepData.physicalNetworkReturned = this.stepData.physicalNetworkItem['createPhysicalNetwork' + index]
|
||||
}
|
||||
@ -943,9 +957,17 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
await this.stepConfigureStorageTraffic()
|
||||
if (this.stepData.isTungstenZone) {
|
||||
await this.stepCreateTungstenFabricPublicNetwork()
|
||||
} else {
|
||||
await this.stepConfigureStorageTraffic()
|
||||
}
|
||||
} else if (this.isAdvancedZone && this.sgEnabled) {
|
||||
await this.stepConfigureStorageTraffic()
|
||||
if (this.stepData.isTungstenZone) {
|
||||
await this.stepCreateTungstenFabricPublicNetwork()
|
||||
} else {
|
||||
await this.stepConfigureStorageTraffic()
|
||||
}
|
||||
} else {
|
||||
if (this.prefillContent.physicalNetworks) {
|
||||
const storageExists = this.prefillContent.physicalNetworks[0].traffics.filter(traffic => traffic.type === 'storage')
|
||||
@ -957,6 +979,56 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
async stepCreateTungstenFabricPublicNetwork () {
|
||||
this.setStepStatus(STATUS_FINISH)
|
||||
this.currentStep++
|
||||
this.addStep('message.create.tungsten.public.network', 'tungsten')
|
||||
if (this.stepData.stepMove.includes('tungsten')) {
|
||||
await this.stepConfigureStorageTraffic()
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (!this.stepData.stepMove.includes('createTungstenFabricProvider')) {
|
||||
const providerParams = {}
|
||||
providerParams.tungstenproviderhostname = this.prefillContent?.tungstenHostname || ''
|
||||
providerParams.name = this.prefillContent?.tungstenName || ''
|
||||
providerParams.zoneid = this.stepData.zoneReturned.id
|
||||
providerParams.tungstenproviderport = this.prefillContent?.tungstenPort || ''
|
||||
providerParams.tungstengateway = this.prefillContent?.tungstenGateway || ''
|
||||
providerParams.tungstenprovidervrouterport = this.prefillContent?.tungstenVrouter || ''
|
||||
providerParams.tungstenproviderintrospectport = this.prefillContent?.tungstenIntrospectPort || ''
|
||||
await this.createTungstenFabricProvider(providerParams)
|
||||
this.stepData.stepMove.push('createTungstenFabricProvider')
|
||||
}
|
||||
if (!this.stepData.stepMove.includes('configTungstenFabricService')) {
|
||||
const configParams = {}
|
||||
configParams.zoneid = this.stepData.zoneReturned.id
|
||||
configParams.physicalnetworkid = this.stepData.tungstenPhysicalNetworkId
|
||||
await this.configTungstenFabricService(configParams)
|
||||
this.stepData.stepMove.push('configTungstenFabricService')
|
||||
}
|
||||
if (!this.stepData.stepMove.includes('createTungstenFabricManagementNetwork')) {
|
||||
const networkParams = {}
|
||||
networkParams.podId = this.stepData.podReturned.id
|
||||
await this.createTungstenFabricManagementNetwork(networkParams)
|
||||
this.stepData.stepMove.push('createTungstenFabricManagementNetwork')
|
||||
}
|
||||
if (!this.sgEnabled) {
|
||||
if (!this.stepData.stepMove.includes('createTungstenFabricPublicNetwork')) {
|
||||
const publicParams = {}
|
||||
publicParams.zoneId = this.stepData.zoneReturned.id
|
||||
await this.createTungstenFabricPublicNetwork(publicParams)
|
||||
this.stepData.stepMove.push('createTungstenFabricPublicNetwork')
|
||||
}
|
||||
}
|
||||
this.stepData.stepMove.push('tungsten')
|
||||
await this.stepConfigureStorageTraffic()
|
||||
} catch (e) {
|
||||
this.messageError = e
|
||||
this.processStatus = STATUS_FAILED
|
||||
this.setStepStatus(STATUS_FAILED)
|
||||
}
|
||||
},
|
||||
async stepConfigureStorageTraffic () {
|
||||
let targetNetwork = false
|
||||
this.prefillContent.physicalNetworks.forEach(physicalNetwork => {
|
||||
@ -1506,7 +1578,7 @@ export default {
|
||||
if (this.prefillContent.secondaryStoragePolicy &&
|
||||
this.prefillContent.secondaryStoragePolicy.value.length > 0) {
|
||||
params['details[' + index.toString() + '].key'] = 'storagepolicy'
|
||||
params['details[' + index.toString() + '].value'] = this.prefillContent.secondaryStoragePolicy.value
|
||||
params['details[' + index.toString() + '].value'] = this.prefillContent.secondaryStoragePolicy
|
||||
index++
|
||||
}
|
||||
}
|
||||
@ -2086,6 +2158,46 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
createTungstenFabricProvider (args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api('createTungstenFabricProvider', {}, 'POST', args).then(json => {
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
const message = error.response.headers['x-description']
|
||||
reject(message)
|
||||
})
|
||||
})
|
||||
},
|
||||
configTungstenFabricService (args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api('configTungstenFabricService', {}, 'POST', args).then(json => {
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
const message = error.response.headers['x-description']
|
||||
reject(message)
|
||||
})
|
||||
})
|
||||
},
|
||||
createTungstenFabricManagementNetwork (args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api('createTungstenFabricManagementNetwork', args).then(json => {
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
const message = error.response.headers['x-description']
|
||||
reject(message)
|
||||
})
|
||||
})
|
||||
},
|
||||
createTungstenFabricPublicNetwork (args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api('createTungstenFabricPublicNetwork', args).then(json => {
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
const message = error.response.headers['x-description']
|
||||
reject(message)
|
||||
})
|
||||
})
|
||||
},
|
||||
nfsURL (server, path) {
|
||||
let url = null
|
||||
if (path.substring(0, 1) !== '/') {
|
||||
|
||||
@ -62,6 +62,18 @@
|
||||
:isFixError="isFixError"
|
||||
/>
|
||||
|
||||
<static-inputs-form
|
||||
v-if="steps && steps[currentStep].formKey === 'tungsten'"
|
||||
@nextPressed="nextPressed"
|
||||
@backPressed="handleBack"
|
||||
@fieldsChanged="fieldsChanged"
|
||||
@submitLaunchZone="submitLaunchZone"
|
||||
:fields="tungstenFields"
|
||||
:prefillContent="prefillContent"
|
||||
:description="tungstenSetupDescription"
|
||||
:isFixError="isFixError"
|
||||
/>
|
||||
|
||||
<static-inputs-form
|
||||
v-if="steps && steps[currentStep].formKey === 'pod'"
|
||||
@nextPressed="nextPressed"
|
||||
@ -167,12 +179,28 @@ export default {
|
||||
return this.zoneType === 'Basic' ||
|
||||
(this.zoneType === 'Advanced' && this.sgEnabled)
|
||||
},
|
||||
isTungstenZone () {
|
||||
let isTungsten = false
|
||||
if (!this.prefillContent.physicalNetworks) {
|
||||
isTungsten = false
|
||||
} else {
|
||||
const tungstenIdx = this.prefillContent.physicalNetworks.findIndex(network => network.isolationMethod === 'TF')
|
||||
isTungsten = tungstenIdx > -1
|
||||
}
|
||||
return isTungsten
|
||||
},
|
||||
allSteps () {
|
||||
const steps = []
|
||||
steps.push({
|
||||
title: 'label.physical.network',
|
||||
formKey: 'physicalNetwork'
|
||||
})
|
||||
if (this.isTungstenZone) {
|
||||
steps.push({
|
||||
title: 'label.tungsten.provider',
|
||||
formKey: 'tungsten'
|
||||
})
|
||||
}
|
||||
if (this.havingNetscaler) {
|
||||
steps.push({
|
||||
title: 'label.netScaler',
|
||||
@ -188,11 +216,13 @@ export default {
|
||||
title: 'label.pod',
|
||||
formKey: 'pod'
|
||||
})
|
||||
steps.push({
|
||||
title: 'label.guest.traffic',
|
||||
formKey: 'guestTraffic',
|
||||
trafficType: 'guest'
|
||||
})
|
||||
if (!this.isTungstenZone) {
|
||||
steps.push({
|
||||
title: 'label.guest.traffic',
|
||||
formKey: 'guestTraffic',
|
||||
trafficType: 'guest'
|
||||
})
|
||||
}
|
||||
steps.push({
|
||||
title: 'label.storage.traffic',
|
||||
formKey: 'storageTraffic',
|
||||
@ -207,6 +237,47 @@ export default {
|
||||
}
|
||||
return {}
|
||||
},
|
||||
tungstenFields () {
|
||||
const fields = [
|
||||
{
|
||||
title: 'label.tungsten.provider.name',
|
||||
key: 'tungstenName',
|
||||
placeHolder: 'message.installwizard.tooltip.tungsten.provider.name',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
title: 'label.tungsten.provider.hostname',
|
||||
key: 'tungstenHostname',
|
||||
placeHolder: 'message.installwizard.tooltip.tungsten.provider.hostname',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
title: 'label.tungsten.provider.gateway',
|
||||
key: 'tungstenGateway',
|
||||
placeHolder: 'message.installwizard.tooltip.tungsten.provider.gateway',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
title: 'label.tungsten.provider.port',
|
||||
key: 'tungstenPort',
|
||||
placeHolder: 'message.installwizard.tooltip.tungsten.provider.port',
|
||||
required: false
|
||||
},
|
||||
{
|
||||
title: 'label.tungsten.provider.vrouterport',
|
||||
key: 'tungstenVrouterport',
|
||||
placeHolder: 'message.installwizard.tooltip.tungsten.provider.vrouterport',
|
||||
required: false
|
||||
},
|
||||
{
|
||||
title: 'label.tungsten.provider.introspectport',
|
||||
key: 'tungstenIntrospectPort',
|
||||
placeHolder: 'message.installwizard.tooltip.tungsten.provider.introspectport',
|
||||
required: false
|
||||
}
|
||||
]
|
||||
return fields
|
||||
},
|
||||
netscalerFields () {
|
||||
return [
|
||||
{
|
||||
@ -344,6 +415,7 @@ export default {
|
||||
basic: 'message.guest.traffic.in.basic.zone'
|
||||
},
|
||||
podSetupDescription: 'message.add.pod.during.zone.creation',
|
||||
tungstenSetupDescription: 'message.infra.setup.tungsten.description',
|
||||
netscalerSetupDescription: 'label.please.specify.netscaler.info',
|
||||
storageTrafficDescription: 'label.zonewizard.traffictype.storage',
|
||||
podFields: [
|
||||
|
||||
@ -29,11 +29,24 @@
|
||||
:columns="columns"
|
||||
:pagination="false"
|
||||
style="margin-bottom: 24px; width: 100%">
|
||||
<template #name="{ text, record }">
|
||||
<a-input :value="text" @change="e => onCellChange(record.key, 'name', e.target.value)" v-focus="true" />
|
||||
<template #name="{ text, record, index }">
|
||||
<a-input
|
||||
:disabled="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
|
||||
:value="text"
|
||||
@change="e => onCellChange(record.key, 'name', e.target.value)"
|
||||
v-focus="true">
|
||||
<template #suffix>
|
||||
<a-tooltip
|
||||
v-if="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
|
||||
:title="$t('message.no.support.tungsten.fabric')">
|
||||
<warning-outlined style="color: #f5222d" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</template>
|
||||
<template #isolationMethod="{ text, record }">
|
||||
<template #isolationMethod="{ text, record, index }">
|
||||
<a-select
|
||||
:disabled="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
|
||||
style="width: 100%"
|
||||
:defaultValue="text"
|
||||
@change="value => onCellChange(record.key, 'isolationMethod', value)"
|
||||
@ -51,9 +64,18 @@
|
||||
<a-select-option value="L3VPN"> L3VPN </a-select-option>
|
||||
<a-select-option value="VSP"> VSP </a-select-option>
|
||||
<a-select-option value="VCS"> VCS </a-select-option>
|
||||
<a-select-option value="TF"> TF </a-select-option>
|
||||
|
||||
<template #suffixIcon>
|
||||
<a-tooltip
|
||||
v-if="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
|
||||
:title="$t('message.no.support.tungsten.fabric')">
|
||||
<warning-outlined style="color: #f5222d" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-select>
|
||||
</template>
|
||||
<template #traffics="{ record }">
|
||||
<template #traffics="{ record, index }">
|
||||
<div v-for="traffic in record.traffics" :key="traffic.type">
|
||||
<a-tag
|
||||
:color="trafficColors[traffic.type]"
|
||||
@ -64,7 +86,7 @@
|
||||
<delete-outlined class="traffic-type-action" @click="deleteTraffic(record.key, traffic, $event)"/>
|
||||
</a-tag>
|
||||
</div>
|
||||
<div v-if="isShowAddTraffic(record.traffics)">
|
||||
<div v-if="isShowAddTraffic(record.traffics, index)">
|
||||
<div class="traffic-select-item" v-if="addingTrafficForKey === record.key">
|
||||
<a-select
|
||||
:defaultValue="trafficLabelSelected"
|
||||
@ -76,9 +98,9 @@
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option
|
||||
v-for="(traffic, index) in availableTrafficToAdd"
|
||||
v-for="(traffic, idx) in availableTrafficToAdd"
|
||||
:value="traffic"
|
||||
:key="index"
|
||||
:key="idx"
|
||||
:disabled="isDisabledTraffic(record.traffics, traffic)"
|
||||
>
|
||||
{{ traffic.toUpperCase() }}
|
||||
@ -111,10 +133,10 @@
|
||||
</a-tag>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions="{ record }">
|
||||
<template #actions="{ record, index }">
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.delete')"
|
||||
v-if="physicalNetworks.indexOf(record) > 0"
|
||||
v-if="tungstenNetworkIndex === -1 ? index > 0 : tungstenNetworkIndex !== index"
|
||||
type="primary"
|
||||
:danger="true"
|
||||
icon="delete-outlined"
|
||||
@ -122,6 +144,7 @@
|
||||
</template>
|
||||
<template #footer v-if="isAdvancedZone">
|
||||
<a-button
|
||||
:disabled="tungstenNetworkIndex > -1"
|
||||
@click="handleAddPhysicalNetwork">
|
||||
{{ $t('label.add.physical.network') }}
|
||||
</a-button>
|
||||
@ -331,6 +354,10 @@ export default {
|
||||
}
|
||||
return traffics
|
||||
},
|
||||
tungstenNetworkIndex () {
|
||||
const tungstenNetworkIndex = this.physicalNetworks.findIndex(network => network.isolationMethod === 'TF')
|
||||
return tungstenNetworkIndex
|
||||
},
|
||||
hypervisor () {
|
||||
return this.prefillContent.hypervisor || null
|
||||
}
|
||||
@ -420,12 +447,16 @@ export default {
|
||||
this.hasUnusedPhysicalNetwork = this.getHasUnusedPhysicalNetwork()
|
||||
},
|
||||
isValidSetup () {
|
||||
const shouldHaveLabels = this.physicalNetworks.length > 1
|
||||
let physicalNetworks = this.physicalNetworks
|
||||
if (this.tungstenNetworkIndex > -1) {
|
||||
physicalNetworks = [this.physicalNetworks[this.tungstenNetworkIndex]]
|
||||
}
|
||||
const shouldHaveLabels = physicalNetworks.length > 1
|
||||
let isValid = true
|
||||
this.requiredTrafficTypes.forEach(type => {
|
||||
if (!isValid) return false
|
||||
let foundType = false
|
||||
this.physicalNetworks.forEach(net => {
|
||||
physicalNetworks.forEach(net => {
|
||||
net.traffics.forEach(traffic => {
|
||||
if (!isValid) return false
|
||||
if (traffic.type === type) {
|
||||
@ -570,7 +601,10 @@ export default {
|
||||
|
||||
return false
|
||||
},
|
||||
isShowAddTraffic (traffics) {
|
||||
isShowAddTraffic (traffics, index) {
|
||||
if (this.tungstenNetworkIndex > -1 && this.tungstenNetworkIndex !== index) {
|
||||
return false
|
||||
}
|
||||
if (!this.availableTrafficToAdd || this.availableTrafficToAdd.length === 0) {
|
||||
return false
|
||||
}
|
||||
@ -618,4 +652,19 @@ export default {
|
||||
margin: 0 0 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled-traffic {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -135,17 +135,24 @@
|
||||
<template #autoscale="{record}">
|
||||
<div>
|
||||
<router-link :to="{ path: '/autoscalevmgroup/' + record.autoscalevmgroup.id }" v-if='record.autoscalevmgroup'>
|
||||
<a-button>{{ $t('label.view') }}</a-button>
|
||||
<a-button>{{ $t('label.view') }}</a-button>
|
||||
</router-link>
|
||||
<router-link :to="{ path: '/action/createAutoScaleVmGroup', query: { networkid: record.networkid, lbruleid : record.id } }" v-else-if='!record.ruleInstances'>
|
||||
<a-button>{{ $t('label.new') }}</a-button>
|
||||
<a-button>{{ $t('label.new') }}</a-button>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
<template #healthmonitor="{ record }">
|
||||
<a-button @click="() => openHealthMonitorModal(record.id)">
|
||||
{{ returnHealthMonitorLabel(record.id) }}
|
||||
</a-button>
|
||||
</template>
|
||||
<template #add="{record}">
|
||||
<a-button type="primary" @click="() => { selectedRule = record; handleOpenAddVMModal() }" v-if='!record.autoscalevmgroup'>
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.add') }}
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
</template>
|
||||
{{ $t('label.add') }}
|
||||
</a-button>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
@ -512,6 +519,84 @@
|
||||
</div>
|
||||
</a-modal>
|
||||
|
||||
<a-modal
|
||||
v-if="healthMonitorModal"
|
||||
:title="$t('label.configure.health.monitor')"
|
||||
:visible="healthMonitorModal"
|
||||
:footer="null"
|
||||
:maskClosable="false"
|
||||
:closable="true"
|
||||
@cancel="closeMonitorModal">
|
||||
<a-form
|
||||
:ref="monitorRef"
|
||||
:model="monitorForm"
|
||||
:rules="monitorRules"
|
||||
layout="vertical"
|
||||
@finish="handleConfigHealthMonitor"
|
||||
v-ctrl-enter="handleConfigHealthMonitor">
|
||||
<a-form-item name="type" ref="type" :label="$t('label.monitor.type')">
|
||||
<a-select
|
||||
v-focus="true"
|
||||
v-model:value="monitorForm.type"
|
||||
@change="(value) => { healthMonitorParams.type = value }"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}">
|
||||
<a-select-option value="PING">PING</a-select-option>
|
||||
<a-select-option value="TCP">TCP</a-select-option>
|
||||
<a-select-option value="HTTP">HTTP</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="retry" ref="retry" :label="$t('label.monitor.retry')">
|
||||
<a-input v-model:value="monitorForm.retry" />
|
||||
</a-form-item>
|
||||
<a-form-item name="timeout" ref="timeout" :label="$t('label.monitor.timeout')">
|
||||
<a-input v-model:value="monitorForm.timeout" />
|
||||
</a-form-item>
|
||||
<a-form-item name="interval" ref="interval" :label="$t('label.monitor.interval')">
|
||||
<a-input v-model:value="monitorForm.interval" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
name="httpmethodtype"
|
||||
ref="httpmethodtype"
|
||||
:label="$t('label.monitor.http.method')"
|
||||
v-if="healthMonitorParams.type === 'HTTP'">
|
||||
<a-select
|
||||
v-focus="true"
|
||||
v-model:value="monitorForm.httpmethodtype"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}">
|
||||
<a-select-option value="GET">GET</a-select-option>
|
||||
<a-select-option value="HEAD">HEAD</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
name="expectedcode"
|
||||
ref="expectedcode"
|
||||
:label="$t('label.monitor.expected.code')"
|
||||
v-if="healthMonitorParams.type === 'HTTP'">
|
||||
<a-input v-model:value="monitorForm.expectedcode" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
name="urlpath"
|
||||
ref="urlpath"
|
||||
:label="$t('label.monitor.url')"
|
||||
v-if="healthMonitorParams.type === 'HTTP'">
|
||||
<a-input v-model:value="monitorForm.urlpath" />
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button :loading="healthMonitorLoading" @click="closeMonitorModal">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button :loading="healthMonitorLoading" type="primary" @click="handleConfigHealthMonitor">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<bulk-action-view
|
||||
v-if="showConfirmationAction || showGroupActionModal"
|
||||
:showConfirmationAction="showConfirmationAction"
|
||||
@ -690,7 +775,19 @@ export default {
|
||||
vmPage: 1,
|
||||
vmPageSize: 10,
|
||||
vmCount: 0,
|
||||
searchQuery: null
|
||||
searchQuery: null,
|
||||
tungstenHealthMonitors: [],
|
||||
healthMonitorModal: false,
|
||||
healthMonitorParams: {
|
||||
type: 'PING',
|
||||
retry: 3,
|
||||
timeout: 5,
|
||||
interval: 5,
|
||||
httpmethodtype: 'GET',
|
||||
expectedcode: undefined,
|
||||
urlpath: '/'
|
||||
},
|
||||
healthMonitorLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -703,6 +800,7 @@ export default {
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.initMonitorForm()
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
@ -722,6 +820,25 @@ export default {
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({})
|
||||
},
|
||||
initMonitorForm () {
|
||||
this.monitorRef = ref()
|
||||
this.monitorForm = reactive({
|
||||
type: this.healthMonitorParams.type,
|
||||
retry: this.healthMonitorParams.retry,
|
||||
timeout: this.healthMonitorParams.timeout,
|
||||
interval: this.healthMonitorParams.interval,
|
||||
httpmethodtype: this.healthMonitorParams.httpmethodtype,
|
||||
expectedcode: this.healthMonitorParams.expectedcode,
|
||||
urlpath: this.healthMonitorParams.urlpath
|
||||
})
|
||||
this.monitorRules = reactive({
|
||||
retry: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
timeout: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
interval: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
expectedcode: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
urlpath: [{ required: true, message: this.$t('message.error.required.input') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
this.fetchListTiers()
|
||||
this.fetchLBRules()
|
||||
@ -737,6 +854,12 @@ export default {
|
||||
}).then(json => {
|
||||
this.tiers.data = json.listnetworksresponse.network || []
|
||||
this.selectedTier = this.tiers.data?.[0]?.id ? this.tiers.data[0].id : null
|
||||
if (this.tiers.data?.[0]?.broadcasturi === 'tf://tf') {
|
||||
this.columns.splice(8, 0, {
|
||||
title: this.$t('label.action.health.monitor'),
|
||||
slots: { customRender: 'healthmonitor' }
|
||||
})
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.tiers.loading = false })
|
||||
@ -760,6 +883,7 @@ export default {
|
||||
this.fetchLBRuleInstances()
|
||||
}, 100)
|
||||
this.fetchLBStickinessPolicies()
|
||||
this.fetchLBTungstenFabricHealthMonitor()
|
||||
this.fetchAutoScaleVMgroups()
|
||||
return
|
||||
}
|
||||
@ -1302,7 +1426,7 @@ export default {
|
||||
newItem.push(...response.listnicsresponse.nic[0].secondaryip.map(ip => ip.ipaddress))
|
||||
}
|
||||
this.nics[index] = newItem
|
||||
this.newRule.vmguestip[index] = this.nics[index][0]
|
||||
this.newRule.vmguestip[index] = [this.nics[index][0]]
|
||||
this.addVmModalNicLoading = false
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
@ -1472,6 +1596,114 @@ export default {
|
||||
onSearch (value) {
|
||||
this.searchQuery = value
|
||||
this.fetchVirtualMachines()
|
||||
},
|
||||
fetchLBTungstenFabricHealthMonitor () {
|
||||
this.tungstenHealthMonitors = []
|
||||
this.loading = true
|
||||
this.lbRules.forEach(rule => {
|
||||
api('listTungstenFabricLBHealthMonitor', {
|
||||
listAll: true,
|
||||
lbruleid: rule.id
|
||||
}).then(response => {
|
||||
const healthmonitor = response?.listtungstenfabriclbhealthmonitorresponse?.healthmonitor || []
|
||||
if (healthmonitor.length > 0) {
|
||||
healthmonitor[0].lbruleid = rule.id
|
||||
this.tungstenHealthMonitors.push(...healthmonitor)
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
returnHealthMonitorLabel (id) {
|
||||
const match = this.tungstenHealthMonitors.filter(item => item.lbruleid === id)
|
||||
if (match.length > 0) {
|
||||
return match[0].type
|
||||
}
|
||||
return this.$t('label.configure')
|
||||
},
|
||||
openHealthMonitorModal (id) {
|
||||
const match = this.tungstenHealthMonitors.filter(item => item.lbruleid === id)
|
||||
this.healthMonitorParams.lbruleid = id
|
||||
if (match.length > 0) {
|
||||
this.healthMonitorParams.type = match[0].type
|
||||
this.healthMonitorParams.retry = match[0].retry
|
||||
this.healthMonitorParams.timeout = match[0].timeout
|
||||
this.healthMonitorParams.interval = match[0].interval
|
||||
this.healthMonitorParams.httpmethodtype = match[0].httpmethod
|
||||
this.healthMonitorParams.expectedcode = match[0].expectedcode
|
||||
this.healthMonitorParams.urlpath = match[0].urlpath
|
||||
}
|
||||
this.initMonitorForm()
|
||||
this.healthMonitorModal = true
|
||||
},
|
||||
closeMonitorModal () {
|
||||
this.healthMonitorModal = false
|
||||
this.healthMonitorParams = {
|
||||
type: 'PING',
|
||||
retry: 3,
|
||||
timeout: 5,
|
||||
interval: 5,
|
||||
httpmethodtype: 'GET',
|
||||
expectedcode: undefined,
|
||||
urlpath: '/'
|
||||
}
|
||||
},
|
||||
handleConfigHealthMonitor () {
|
||||
if (this.healthMonitorLoading) return
|
||||
|
||||
this.monitorRef.value.validate().then(() => {
|
||||
const values = toRaw(this.monitorForm)
|
||||
|
||||
this.healthMonitorParams.type = values.type
|
||||
this.healthMonitorParams.retry = values.retry
|
||||
this.healthMonitorParams.timeout = values.timeout
|
||||
this.healthMonitorParams.interval = values.interval
|
||||
if (values.type === 'HTTP') {
|
||||
this.healthMonitorParams.httpmethodtype = values.httpmethodtype
|
||||
this.healthMonitorParams.expectedcode = values.expectedcode
|
||||
this.healthMonitorParams.urlpath = values.urlpath
|
||||
}
|
||||
|
||||
this.healthMonitorLoading = true
|
||||
api('updateTungstenFabricLBHealthMonitor', this.healthMonitorParams).then(json => {
|
||||
const jobId = json?.updatetungstenfabriclbhealthmonitorresponse?.jobid
|
||||
this.$pollJob({
|
||||
jobId: jobId,
|
||||
successMessage: this.$t('message.success.config.health.monitor'),
|
||||
successMethod: () => {
|
||||
this.parentToggleLoading()
|
||||
this.fetchData()
|
||||
this.closeMonitorModal()
|
||||
this.healthMonitorLoading = false
|
||||
},
|
||||
errorMessage: this.$t('message.config.health.monitor.failed'),
|
||||
errorMethod: () => {
|
||||
this.parentToggleLoading()
|
||||
this.fetchData()
|
||||
this.closeMonitorModal()
|
||||
this.healthMonitorLoading = false
|
||||
},
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.parentToggleLoading()
|
||||
this.fetchData()
|
||||
this.closeMonitorModal()
|
||||
this.healthMonitorLoading = false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.healthMonitorLoading = false
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.monitorRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.healthMonitorLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
<a-input
|
||||
v-model:value="form.name"
|
||||
:placeholder="apiParams.name.description"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
</a-form-item>
|
||||
<a-form-item name="displaytext" ref="displaytext">
|
||||
<template #label>
|
||||
@ -41,7 +41,7 @@
|
||||
<a-input
|
||||
v-model:value="form.displaytext"
|
||||
:placeholder="apiParams.displaytext.description"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
</a-form-item>
|
||||
<div v-if="setMTU">
|
||||
<a-row :gutter="12" v-if="resource.type !== 'L2'">
|
||||
@ -130,7 +130,7 @@
|
||||
<a-input
|
||||
v-model:value="form.networkdomain"
|
||||
:placeholder="apiParams.networkdomain.description"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
</a-form-item>
|
||||
<a-form-item name="updateinsequence" ref="updateinsequence" v-if="resource.redundantrouter">
|
||||
<template #label>
|
||||
|
||||
309
ui/src/views/network/tungsten/FirewallPolicyTab.vue
Normal file
309
ui/src/views/network/tungsten/FirewallPolicyTab.vue
Normal file
@ -0,0 +1,309 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-spin :spinning="loading">
|
||||
<a-button
|
||||
:disabled="!('createTungstenFabricFirewallPolicy' in $store.getters.apis)"
|
||||
type="dashed"
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="addFirewallPolicy">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.add.tungsten.firewall.policy') }}
|
||||
</a-button>
|
||||
<a-table
|
||||
size="small"
|
||||
style="overflow-y: auto"
|
||||
:loading="fetchLoading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="item => item.uuid"
|
||||
:pagination="false">
|
||||
<template #name="{ text, record }">
|
||||
<router-link :to="{ path: '/tungstenfirewallpolicy/' + record.uuid, query: { zoneid: zoneId } }">{{ text }}</router-link>
|
||||
</template>
|
||||
<template #firewallrule="{ record }">
|
||||
<span v-if="record.firewallrule.length > 0">{{ record.firewallrule[0].name }}</span>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<a-popconfirm
|
||||
:title="$t('label.confirm.delete.tungsten.firewall.policy')"
|
||||
@confirm="removeFirewallRule(record.uuid)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')">
|
||||
<tooltip-button
|
||||
tooltipPlacement="bottom"
|
||||
:tooltip="$t('label.delete.tungsten.firewall.policy')"
|
||||
danger
|
||||
type="primary"
|
||||
icon="delete-outlined"
|
||||
:loading="deleteLoading" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
<div style="display: block; text-align: right; margin-top: 10px;">
|
||||
<a-pagination
|
||||
class="row-element pagination"
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="totalCount"
|
||||
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="['10', '20', '40', '80', '100']"
|
||||
@change="changePage"
|
||||
@showSizeChange="changePageSize"
|
||||
showSizeChanger>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
<a-modal
|
||||
v-if="firewallPolicyModal"
|
||||
:visible="firewallPolicyModal"
|
||||
:title="$t('label.add.tungsten.firewall.policy')"
|
||||
:closable="true"
|
||||
:footer="null"
|
||||
@cancel="closeAction"
|
||||
centered
|
||||
width="450px">
|
||||
<div v-ctrl-enter="submitFirewallPolicy">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical">
|
||||
<a-form-item name="name" ref="name">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-focus="true"
|
||||
v-model:value="form.name"
|
||||
:placeholder="apiParams.name.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="sequence" ref="sequence">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.sequence')" :tooltip="apiParams.sequence.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.sequence"
|
||||
:placeholder="apiParams.sequence.description"/>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button ref="submit" type="primary" @click="submitFirewallPolicy" :loading="addLoading">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
|
||||
export default {
|
||||
name: 'FirewallPolicyTab',
|
||||
components: {
|
||||
TooltipLabel,
|
||||
TooltipButton
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
zoneId: undefined,
|
||||
fetchLoading: false,
|
||||
firewallPolicyModal: false,
|
||||
addLoading: false,
|
||||
deleteLoading: false,
|
||||
columns: [{
|
||||
title: this.$t('label.name'),
|
||||
dataIndex: 'name',
|
||||
slots: { customRender: 'name' }
|
||||
}, {
|
||||
title: this.$t('label.firewallrule'),
|
||||
dataIndex: 'firewallrule',
|
||||
slots: { customRender: 'firewallrule' }
|
||||
}, {
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 80
|
||||
}],
|
||||
dataSource: [],
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
totalCount: 0
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('createTungstenFabricFirewallRule')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({
|
||||
name: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
sequence: [{ required: true, message: this.$t('message.error.required.input') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (!this.resource.uuid || !('zoneid' in this.$route.query)) {
|
||||
return
|
||||
}
|
||||
this.zoneId = this.$route.query.zoneid
|
||||
this.fetchLoading = true
|
||||
this.dataSource = []
|
||||
this.totalCount = 0
|
||||
api('listTungstenFabricFirewallPolicy', {
|
||||
zoneid: this.zoneId,
|
||||
applicationpolicysetuuid: this.resource.uuid,
|
||||
page: this.page,
|
||||
pagesize: this.pageSize
|
||||
}).then(json => {
|
||||
this.dataSource = json?.listtungstenfabricfirewallpolicyresponse?.firewallpolicy || []
|
||||
this.totalCount = json?.listtungstenfabricfirewallpolicyresponse?.count || 0
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.fetchLoading = false
|
||||
})
|
||||
},
|
||||
addFirewallPolicy () {
|
||||
this.firewallPolicyModal = true
|
||||
},
|
||||
submitFirewallPolicy () {
|
||||
if (this.addLoading) return
|
||||
this.addLoading = true
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
const params = {}
|
||||
params.applicationpolicysetuuid = this.resource.uuid
|
||||
params.zoneid = this.zoneId
|
||||
params.name = values.name
|
||||
params.sequence = values.sequence
|
||||
|
||||
api('createTungstenFabricFirewallPolicy', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.createtungstenfabricfirewallpolicyresponse.jobid,
|
||||
title: this.$t('label.add.tungsten.firewall.policy'),
|
||||
description: params.name,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
this.firewallPolicyModal = false
|
||||
},
|
||||
errorMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
},
|
||||
loadingMessage: this.$t('message.adding.firewall.policy'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.addLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.addLoading = false
|
||||
})
|
||||
},
|
||||
removeFirewallRule (uuid) {
|
||||
if (this.deleteLoading) return
|
||||
this.deleteLoading = true
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.firewallpolicyuuid = uuid
|
||||
|
||||
api('deleteTungstenFabricFirewallPolicy', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.deletetungstenfabricfirewallpolicyresponse.jobid,
|
||||
title: this.$t('label.delete.tungsten.firewall.policy'),
|
||||
description: params.firewallpolicyuuid,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
errorMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
loadingMessage: this.$t('message.deleting.firewall.policy'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.deleteLoading = false
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.firewallPolicyModal = false
|
||||
this.formRef.value.resetFields()
|
||||
},
|
||||
changePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
changePageSize (currentPage, pageSize) {
|
||||
this.page = currentPage
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
616
ui/src/views/network/tungsten/FirewallRuleTab.vue
Normal file
616
ui/src/views/network/tungsten/FirewallRuleTab.vue
Normal file
@ -0,0 +1,616 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-spin :spinning="loading">
|
||||
<a-button
|
||||
:disabled="!('createTungstenFabricFirewallRule' in $store.getters.apis)"
|
||||
type="dashed"
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="addFirewallRule">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.add.firewallrule') }}
|
||||
</a-button>
|
||||
<a-table
|
||||
size="small"
|
||||
style="overflow-y: auto"
|
||||
:loading="fetchLoading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="item => item.uuid"
|
||||
:pagination="false">
|
||||
<template #actions="{ record }">
|
||||
<a-popconfirm
|
||||
:title="$t('message.confirm.remove.firewall.rule')"
|
||||
@confirm="removeFirewallRule(record.uuid)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')">
|
||||
<tooltip-button
|
||||
tooltipPlacement="bottom"
|
||||
:tooltip="$t('label.remove.firewall.rule')"
|
||||
danger
|
||||
type="primary"
|
||||
icon="delete-outlined"
|
||||
:loading="deleteLoading" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
<div style="display: block; text-align: right; margin-top: 10px;">
|
||||
<a-pagination
|
||||
class="row-element pagination"
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="totalCount"
|
||||
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="['10', '20', '40', '80', '100']"
|
||||
@change="changePage"
|
||||
@showSizeChange="changePageSize"
|
||||
showSizeChanger>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
<a-modal
|
||||
v-if="firewallRuleModal"
|
||||
:visible="firewallRuleModal"
|
||||
:title="$t('label.add.tungsten.firewall.policy')"
|
||||
:closable="true"
|
||||
:footer="null"
|
||||
@cancel="closeAction"
|
||||
centered
|
||||
width="450px">
|
||||
<div v-ctrl-enter="submitFirewallRule">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical">
|
||||
<a-form-item name="name" ref="name">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-focus="true"
|
||||
v-model:value="form.name"
|
||||
:placeholder="apiParams.name.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="action" ref="action">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.action')" :tooltip="apiParams.action.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.action"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:placeholder="apiParams.action.description">
|
||||
<a-select-option value="pass">PASS</a-select-option>
|
||||
<a-select-option value="deny">DENY</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="servicegroupuuid" ref="servicegroupuuid">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.servicegroupuuid')" :tooltip="apiParams.servicegroupuuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.servicegroupuuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="serviceGroup.loading"
|
||||
:placeholder="apiParams.servicegroupuuid.description">
|
||||
<a-select-option v-for="group in serviceGroup.opts" :key="group.uuid">
|
||||
{{ group.name || group.description || group.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="sourcetype" ref="sourcetype">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.sourcetype')" :tooltip="$t('label.sourcetype')"/>
|
||||
</template>
|
||||
<a-select v-model:value="form.sourcetype">
|
||||
<a-select-option value="srctag">{{ $t('label.tag') }}</a-select-option>
|
||||
<a-select-option value="srcaddress">{{ $t('label.group') }}</a-select-option>
|
||||
<a-select-option value="srcnetwork">{{ $t('label.network') }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="srctaguuid" ref="srctaguuid" v-if="form.sourcetype === 'srctag'">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srctaguuid')" :tooltip="apiParams.srctaguuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.srctaguuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="srcTag.loading"
|
||||
:placeholder="apiParams.srctaguuid.description">
|
||||
<a-select-option v-for="tag in srcTag.opts" :key="tag.uuid">
|
||||
{{ tag.name || tag.description || tag.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="srcaddressgroupuuid" ref="srcaddressgroupuuid" v-if="form.sourcetype === 'srcaddress'">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srcaddressgroupuuid')" :tooltip="apiParams.srcaddressgroupuuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.srcaddressgroupuuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="srcAddress.loading"
|
||||
:placeholder="apiParams.srcaddressgroupuuid.description">
|
||||
<a-select-option v-for="address in srcAddress.opts" :key="address.uuid">
|
||||
{{ address.name || address.description || address.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="srcnetworkuuid" ref="srcnetworkuuid" v-if="form.sourcetype === 'srcnetwork'">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srcnetworkuuid')" :tooltip="apiParams.srcnetworkuuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.srcnetworkuuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="networks.loading"
|
||||
:placeholder="apiParams.srcnetworkuuid.description">
|
||||
<a-select-option v-for="network in networks.opts" :key="network.uuid">
|
||||
{{ network.name || network.description || network.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="direction" ref="direction">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.direction')" :tooltip="apiParams.direction.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.direction"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:placeholder="apiParams.direction.description">
|
||||
<a-select-option value="oneway">ONE WAY</a-select-option>
|
||||
<a-select-option value="twoway">TWO WAY</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="sourcetype" ref="sourcetype">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.destinationtype')" :tooltip="$t('label.destinationtype')"/>
|
||||
</template>
|
||||
<a-select v-model:value="form.destinationtype">
|
||||
<a-select-option value="destag">{{ $t('label.tag') }}</a-select-option>
|
||||
<a-select-option value="desaddress">{{ $t('label.group') }}</a-select-option>
|
||||
<a-select-option value="desnetwork">{{ $t('label.network') }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="desttaguuid" ref="desttaguuid" v-if="form.destinationtype === 'destag'">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.desttaguuid')" :tooltip="apiParams.desttaguuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.desttaguuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="srcTag.loading"
|
||||
:placeholder="apiParams.desttaguuid.description">
|
||||
<a-select-option v-for="tag in srcTag.opts" :key="tag.uuid">
|
||||
{{ tag.name || tag.description || tag.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="destaddressgroupuuid" ref="destaddressgroupuuid" v-if="form.destinationtype === 'desaddress'">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.destaddressgroupuuid')" :tooltip="apiParams.destaddressgroupuuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.destaddressgroupuuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="srcAddress.loading"
|
||||
:placeholder="apiParams.destaddressgroupuuid.description">
|
||||
<a-select-option v-for="address in srcAddress.opts" :key="address.uuid">
|
||||
{{ address.name || address.description || address.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="destnetworkuuid" ref="destnetworkuuid" v-if="form.destinationtype === 'desnetwork'">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.destnetworkuuid')" :tooltip="apiParams.destnetworkuuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.destnetworkuuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="networks.loading"
|
||||
:placeholder="apiParams.destnetworkuuid.description">
|
||||
<a-select-option v-for="network in networks.opts" :key="network.uuid">
|
||||
{{ network.name || network.description || network.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="tagtypeuuid" ref="tagtypeuuid">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.tagtypeuuid')" :tooltip="apiParams.tagtypeuuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.tagtypeuuid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="tagType.loading"
|
||||
:placeholder="apiParams.tagtypeuuid.description">
|
||||
<a-select-option v-for="tag in tagType.opts" :key="tag.uuid">
|
||||
{{ tag.name || tag.description || tag.displaytext }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="sequence" ref="sequence">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.sequence')" :tooltip="apiParams.sequence.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-focus="true"
|
||||
v-model:value="form.sequence"
|
||||
:placeholder="apiParams.sequence.description"/>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button ref="submit" type="primary" @click="submitFirewallRule" :loading="addLoading">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
|
||||
export default {
|
||||
name: 'FirewallRuleTab',
|
||||
components: {
|
||||
TooltipLabel,
|
||||
TooltipButton
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
zoneId: undefined,
|
||||
fetchLoading: false,
|
||||
firewallRuleModal: false,
|
||||
addLoading: false,
|
||||
deleteLoading: false,
|
||||
columns: [{
|
||||
title: this.$t('label.name'),
|
||||
dataIndex: 'name'
|
||||
}, {
|
||||
title: this.$t('label.action'),
|
||||
dataIndex: 'action'
|
||||
}, {
|
||||
title: this.$t('label.servicegroupuuid'),
|
||||
dataIndex: 'servicegroup'
|
||||
}, {
|
||||
title: this.$t('label.srcaddressgroupuuid'),
|
||||
dataIndex: 'srctag'
|
||||
}, {
|
||||
title: this.$t('label.direction'),
|
||||
dataIndex: 'direction'
|
||||
}, {
|
||||
title: this.$t('label.destaddressgroupuuid'),
|
||||
dataIndex: 'desttag'
|
||||
}, {
|
||||
title: this.$t('label.tagtypeuuid'),
|
||||
dataIndex: 'tagtype'
|
||||
}, {
|
||||
title: this.$t('label.actions'),
|
||||
slots: { customRender: 'actions' },
|
||||
width: 80
|
||||
}],
|
||||
dataSource: [],
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
totalCount: 0,
|
||||
serviceGroup: {
|
||||
loading: false,
|
||||
opts: []
|
||||
},
|
||||
srcTag: {
|
||||
loading: false,
|
||||
opts: []
|
||||
},
|
||||
srcAddress: {
|
||||
loading: false,
|
||||
opts: []
|
||||
},
|
||||
networks: {
|
||||
loading: false,
|
||||
opts: []
|
||||
},
|
||||
tagType: {
|
||||
loading: false,
|
||||
opts: []
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('createTungstenFabricFirewallRule')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({
|
||||
action: 'pass',
|
||||
direction: 'oneway',
|
||||
sequence: 1,
|
||||
sourcetype: 'srctag',
|
||||
destinationtype: 'destag'
|
||||
})
|
||||
this.rules = reactive({
|
||||
name: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
action: [{ required: true, message: this.$t('message.error.select') }],
|
||||
servicegroupuuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
srctaguuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
srcaddressgroupuuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
srcnetworkuuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
direction: [{ required: true, message: this.$t('message.error.select') }],
|
||||
desttaguuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
destaddressgroupuuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
destnetworkuuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
sequence: [{ required: true, message: this.$t('message.error.required.input') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (!this.resource.uuid || !('zoneid' in this.$route.query)) {
|
||||
return
|
||||
}
|
||||
this.zoneId = this.$route.query.zoneid
|
||||
this.fetchLoading = true
|
||||
this.dataSource = []
|
||||
this.totalCount = 0
|
||||
api('listTungstenFabricFirewallRule', {
|
||||
zoneid: this.zoneId,
|
||||
firewallpolicyuuid: this.resource.uuid,
|
||||
page: this.page,
|
||||
pagesize: this.pageSize,
|
||||
listAll: true
|
||||
}).then(json => {
|
||||
this.dataSource = json?.listtungstenfabricfirewallruleresponse?.firewallrule || []
|
||||
this.totalCount = json?.listtungstenfabricfirewallruleresponse?.count || 0
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.fetchLoading = false
|
||||
})
|
||||
},
|
||||
addFirewallRule () {
|
||||
this.firewallRuleModal = true
|
||||
this.fetchServiceGroup()
|
||||
this.fetchTag()
|
||||
this.fetchAddressGroup()
|
||||
this.fetchNetworks()
|
||||
this.fetchTagType()
|
||||
},
|
||||
fetchServiceGroup () {
|
||||
this.serviceGroup.loading = true
|
||||
this.serviceGroup.opts = []
|
||||
api('listTungstenFabricServiceGroup', { zoneid: this.zoneId }).then(json => {
|
||||
this.serviceGroup.opts = json?.listtungstenfabricservicegroupresponse?.servicegroup || []
|
||||
}).finally(() => {
|
||||
this.serviceGroup.loading = false
|
||||
})
|
||||
},
|
||||
fetchTag () {
|
||||
this.srcTag.loading = true
|
||||
this.srcTag.opts = []
|
||||
api('listTungstenFabricTag', { zoneid: this.zoneId }).then(json => {
|
||||
this.srcTag.opts = json?.listtungstenfabrictagresponse?.tag || []
|
||||
}).finally(() => {
|
||||
this.srcTag.loading = false
|
||||
})
|
||||
},
|
||||
fetchAddressGroup () {
|
||||
this.srcAddress.loading = true
|
||||
this.srcAddress.opts = []
|
||||
api('listTungstenFabricAddressGroup', { zoneid: this.zoneId }).then(json => {
|
||||
this.srcAddress.opts = json?.listtungstenfabricaddressgroupresponse?.addressgroup || []
|
||||
}).finally(() => {
|
||||
this.srcAddress.loading = false
|
||||
})
|
||||
},
|
||||
fetchNetworks () {
|
||||
this.networks.loading = true
|
||||
this.networks.opts = []
|
||||
api('listTungstenFabricNetwork', { zoneid: this.zoneId, listAll: true }).then(json => {
|
||||
this.networks.opts = json?.listtungstenfabricnetworkresponse?.network || []
|
||||
}).finally(() => {
|
||||
this.networks.loading = false
|
||||
})
|
||||
},
|
||||
fetchTagType () {
|
||||
this.tagType.loading = true
|
||||
this.tagType.opts = []
|
||||
api('listTungstenFabricTagType', { zoneid: this.zoneId }).then(json => {
|
||||
this.tagType.opts = json?.listtungstenfabrictagtyperesponse?.tagtype || []
|
||||
}).finally(() => {
|
||||
this.tagType.loading = false
|
||||
})
|
||||
},
|
||||
submitFirewallRule () {
|
||||
if (this.addLoading) return
|
||||
this.addLoading = true
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
const params = {}
|
||||
params.firewallpolicyuuid = this.resource.uuid
|
||||
params.zoneid = this.zoneId
|
||||
params.name = values.name
|
||||
params.action = values.action
|
||||
params.servicegroupuuid = values.servicegroupuuid
|
||||
params.direction = values.direction
|
||||
params.sequence = values.sequence
|
||||
if (values.sourcetype === 'srctag') {
|
||||
params.srctaguuid = values.srctaguuid
|
||||
} else if (values.sourcetype === 'srcaddress') {
|
||||
params.srcaddressgroupuuid = values.srcaddressgroupuuid
|
||||
} else if (values.sourcetype === 'srcnetwork') {
|
||||
params.srcnetworkuuid = values.srcnetworkuuid
|
||||
}
|
||||
if (values.destinationtype === 'destag') {
|
||||
params.desttaguuid = values.desttaguuid
|
||||
} else if (values.destinationtype === 'desaddress') {
|
||||
params.destaddressgroupuuid = values.destaddressgroupuuid
|
||||
} else if (values.destinationtype === 'desnetwork') {
|
||||
params.destnetworkuuid = values.destnetworkuuid
|
||||
}
|
||||
params.tagtypeuuid = values.tagtypeuuid
|
||||
|
||||
api('createTungstenFabricFirewallRule', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.createtungstenfabricfirewallruleresponse.jobid,
|
||||
title: this.$t('label.add.firewallrule'),
|
||||
description: params.name,
|
||||
successMessage: this.$t('message.success.add.firewallrule'),
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
this.firewallRuleModal = false
|
||||
},
|
||||
errorMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
},
|
||||
errorMessage: this.$t('message.add.firewallrule.failed'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.addLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.addLoading = false
|
||||
})
|
||||
},
|
||||
removeFirewallRule (uuid) {
|
||||
if (this.deleteLoading) return
|
||||
this.deleteLoading = true
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.firewallruleuuid = uuid
|
||||
|
||||
api('deleteTungstenFabricFirewallRule', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.deletetungstenfabricfirewallruleresponse.jobid,
|
||||
title: this.$t('label.delete.tungsten.firewall.policy'),
|
||||
description: params.firewallpolicyuuid,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
errorMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
loadingMessage: this.$t('message.deleting.firewall.policy'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).finally(() => {
|
||||
this.deleteLoading = false
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.firewallRuleModal = false
|
||||
this.formRef.value.resetFields()
|
||||
},
|
||||
changePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
changePageSize (currentPage, pageSize) {
|
||||
this.page = currentPage
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
315
ui/src/views/network/tungsten/FirewallTagTab.vue
Normal file
315
ui/src/views/network/tungsten/FirewallTagTab.vue
Normal file
@ -0,0 +1,315 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-spin :spinning="loading">
|
||||
<a-button
|
||||
:disabled="!('applyTungstenFabricTag' in $store.getters.apis)"
|
||||
type="dashed"
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="applyTag">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.apply.tungsten.tag') }}
|
||||
</a-button>
|
||||
<a-table
|
||||
size="small"
|
||||
style="overflow-y: auto"
|
||||
:loading="fetchLoading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="item => item.uuid"
|
||||
:pagination="false">
|
||||
<template #action="{ record }">
|
||||
<a-popconfirm
|
||||
:title="$t('message.delete.tungsten.tag')"
|
||||
@confirm="removeTag(record.uuid)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')">
|
||||
<tooltip-button
|
||||
tooltipPlacement="bottom"
|
||||
:tooltip="$t('label.remove.tag')"
|
||||
danger
|
||||
type="primary"
|
||||
icon="delete-outlined"
|
||||
:loading="deleteLoading" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-divider/>
|
||||
<a-pagination
|
||||
class="row-element pagination"
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="totalCount"
|
||||
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="['10', '20', '40', '80', '100']"
|
||||
@change="changePage"
|
||||
@showSizeChange="changePageSize"
|
||||
showSizeChanger>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</a-spin>
|
||||
|
||||
<a-modal
|
||||
v-if="tagModal"
|
||||
:visible="tagModal"
|
||||
:title="$t('label.add.tungsten.firewall.policy')"
|
||||
:closable="true"
|
||||
:footer="null"
|
||||
@cancel="closeAction"
|
||||
centered
|
||||
width="450px">
|
||||
<div v-ctrl-enter="handleSubmit">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical">
|
||||
<a-form-item name="taguuid" ref="taguuid">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.taguuid')" :tooltip="apiParams.taguuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-focus="true"
|
||||
:loading="tagSrc.loading"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="form.taguuid"
|
||||
:placeholder="apiParams.taguuid.description">
|
||||
<a-select-option v-for="opt in tagSrc.opts" :key="opt.uuid">{{ opt.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button ref="submit" type="primary" @click="handleSubmit" :loading="addLoading">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
|
||||
export default {
|
||||
name: 'FirewallTagTab',
|
||||
components: {
|
||||
TooltipLabel,
|
||||
TooltipButton
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
zoneId: undefined,
|
||||
fetchLoading: false,
|
||||
deleteLoading: false,
|
||||
addLoading: false,
|
||||
tagModal: false,
|
||||
dataSource: [],
|
||||
columns: [{
|
||||
title: this.$t('label.name'),
|
||||
dataIndex: 'name'
|
||||
}, {
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 80
|
||||
}],
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
totalCount: 0,
|
||||
tagSrc: {
|
||||
loading: false,
|
||||
opts: []
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('applyTungstenFabricTag')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({
|
||||
taguuid: [{ required: true, message: this.$t('message.error.select') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (!this.resource.uuid || !('zoneid' in this.$route.query)) {
|
||||
return
|
||||
}
|
||||
this.zoneId = this.$route.query.zoneid
|
||||
this.fetchLoading = true
|
||||
this.dataSource = []
|
||||
this.totalCount = 0
|
||||
api('listTungstenFabricTag', {
|
||||
zoneid: this.zoneId,
|
||||
applicationpolicysetuuid: this.resource.uuid,
|
||||
page: this.page,
|
||||
pagesize: this.pageSize
|
||||
}).then(json => {
|
||||
this.dataSource = json?.listtungstenfabrictagresponse?.tag || []
|
||||
this.totalCount = json?.listtungstenfabrictagresponse?.count || 0
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.fetchLoading = false
|
||||
})
|
||||
},
|
||||
fetchTag () {
|
||||
this.tagSrc.loading = true
|
||||
this.tagSrc.opts = []
|
||||
api('listTungstenFabricTag', { zoneid: this.zoneId }).then(json => {
|
||||
this.tagSrc.opts = json?.listtungstenfabrictagresponse?.tag || []
|
||||
}).finally(() => {
|
||||
this.tagSrc.loading = true
|
||||
})
|
||||
},
|
||||
applyTag () {
|
||||
this.tagModal = true
|
||||
this.fetchTag()
|
||||
},
|
||||
handleSubmit () {
|
||||
if (this.addLoading) return
|
||||
this.addLoading = true
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
const params = {}
|
||||
params.applicationpolicysetuuid = this.resource.uuid
|
||||
params.zoneid = this.zoneId
|
||||
params.taguuid = values.taguuid
|
||||
|
||||
const tag = this.tagSrc.opts.filter(tag => tag.uuid === params.taguuid)
|
||||
const description = tag[0]?.name || values.taguuid
|
||||
|
||||
api('applyTungstenFabricTag', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.applytungstenfabrictagresponse.jobid,
|
||||
title: this.$t('label.apply.tungsten.tag'),
|
||||
description,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
this.tagModal = false
|
||||
},
|
||||
errorMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
},
|
||||
loadingMessage: this.$t('message.adding.tag'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
this.addLoading = false
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.addLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.addLoading = false
|
||||
})
|
||||
},
|
||||
removeTag (uuid) {
|
||||
if (this.deleteLoading) return
|
||||
this.deleteLoading = true
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.applicationpolicysetuuid = this.resource.uuid
|
||||
params.taguuid = uuid
|
||||
|
||||
api('removeTungstenFabricTag', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.removetungstenfabrictagresponse.jobid,
|
||||
title: this.$t('label.delete.tungsten.firewall.policy'),
|
||||
description: uuid,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
errorMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
loadingMessage: this.$t('message.deleting.firewall.policy'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
this.deleteLoading = false
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.deleteLoading = false
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.tagModal = false
|
||||
if (this.formRef?.value) {
|
||||
this.formRef.value.resetFields()
|
||||
}
|
||||
},
|
||||
changePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
changePageSize (currentPage, pageSize) {
|
||||
this.page = currentPage
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
243
ui/src/views/network/tungsten/LogicalRouterTab.vue
Normal file
243
ui/src/views/network/tungsten/LogicalRouterTab.vue
Normal file
@ -0,0 +1,243 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-button
|
||||
:disabled="!('addTungstenFabricNetworkGatewayToLogicalRouter' in $store.getters.apis)"
|
||||
type="dashed"
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="onShowAction">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.add.logical.router') }}
|
||||
</a-button>
|
||||
<a-table
|
||||
size="small"
|
||||
:loading="fetchLoading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="(item, index) => index"
|
||||
:pagination="false">
|
||||
</a-table>
|
||||
<div style="display: block; text-align: right; margin-top: 10px;">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="itemCount"
|
||||
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="pageSizeOptions"
|
||||
@change="changePage"
|
||||
@showSizeChange="changePageSize"
|
||||
showSizeChanger>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
|
||||
<a-modal
|
||||
v-if="showAction"
|
||||
:visible="showAction"
|
||||
:title="$t('label.add.logical.router')"
|
||||
:maskClosable="false"
|
||||
:footer="null"
|
||||
@cancel="showAction = false">
|
||||
<div v-ctrl-enter="handleSubmit">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical">
|
||||
<a-form-item name="logicalrouteruuid" ref="logicalrouteruuid" :label="$t('label.tungsten.logical.router')">
|
||||
<a-select
|
||||
:loading="logicalRouters.loading"
|
||||
v-model:value="form.logicalrouteruuid">
|
||||
<a-select-option v-for="logicalRouter in logicalRouters.opts" :key="logicalRouter.uuid">{{ logicalRouter.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="() => { showAction = false }">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button type="primary" ref="submit" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import { mixinDevice } from '@/utils/mixin.js'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
|
||||
export default {
|
||||
name: 'LogicalRouterTab',
|
||||
components: { TooltipButton },
|
||||
mixins: [mixinDevice],
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
fetchLoading: false,
|
||||
deleteLoading: false,
|
||||
submitLoading: false,
|
||||
showAction: false,
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
itemCount: 0,
|
||||
columns: [{
|
||||
title: this.$t('label.name'),
|
||||
dataIndex: 'name'
|
||||
}, {
|
||||
title: this.$t('label.action'),
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
width: 80
|
||||
}],
|
||||
dataSource: [],
|
||||
logicalRouters: {
|
||||
loading: false,
|
||||
opts: []
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource (newData, oldData) {
|
||||
if (newData !== oldData) {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
},
|
||||
computed: {
|
||||
pageSizeOptions () {
|
||||
const sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
|
||||
if (this.device !== 'desktop') {
|
||||
sizes.unshift(10)
|
||||
}
|
||||
return [...new Set(sizes)].sort(function (a, b) {
|
||||
return a - b
|
||||
}).map(String)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({
|
||||
logicalrouteruuid: [{ required: true, message: this.$t('message.error.select') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (Object.keys(this.resource).length === 0) {
|
||||
return
|
||||
}
|
||||
const params = {}
|
||||
params.zoneid = this.resource.zoneid
|
||||
params.networkuuid = this.resource.id
|
||||
params.listAll = true
|
||||
params.page = this.page
|
||||
params.pagesize = this.pageSize
|
||||
|
||||
this.itemCount = 0
|
||||
this.dataSource = []
|
||||
this.fetchLoading = true
|
||||
|
||||
api('listTungstenFabricLogicalRouter', params).then(json => {
|
||||
this.itemCount = json?.listtungstenfabriclogicalrouterresponse?.count || 0
|
||||
this.dataSource = json?.listtungstenfabriclogicalrouterresponse?.logicalrouter || []
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.fetchLoading = false })
|
||||
},
|
||||
onShowAction () {
|
||||
this.showAction = true
|
||||
this.logicalRouters.loading = true
|
||||
this.logicalRouters.opts = []
|
||||
api('listTungstenFabricLogicalRouter', { zoneid: this.resource.zoneid }).then(json => {
|
||||
this.logicalRouters.opts = json?.listtungstenfabriclogicalrouterresponse?.logicalrouter || []
|
||||
this.form.logicalrouteruuid = this.logicalRouters.opts[0]?.uuid || null
|
||||
}).finally(() => {
|
||||
this.logicalRouters.loading = false
|
||||
})
|
||||
},
|
||||
changePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
changePageSize (currentPage, pageSize) {
|
||||
this.page = currentPage
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
handleSubmit () {
|
||||
if (this.submitLoading) return
|
||||
this.submitLoading = true
|
||||
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
|
||||
const params = {}
|
||||
params.zoneid = this.resource.zoneid
|
||||
params.networkuuid = this.resource.id
|
||||
params.logicalrouteruuid = values.logicalrouteruuid
|
||||
|
||||
api('addTungstenFabricNetworkGatewayToLogicalRouter', params).then(json => {
|
||||
const jobId = json?.addtungstenfabricnetworkgatewaytologicalrouterresponse?.jobid
|
||||
this.$pollJob({
|
||||
jobId,
|
||||
title: this.$t('label.add.logical.router'),
|
||||
description: values.logicalrouteruuid,
|
||||
successMessage: `${this.$t('message.success.add.logical.router')} ${values.logicalrouteruuid}`,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
errorMessage: this.$t('message.error.add.logical.router'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.showAction = false
|
||||
this.submitLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.submitLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
332
ui/src/views/network/tungsten/NetworkPolicyTab.vue
Normal file
332
ui/src/views/network/tungsten/NetworkPolicyTab.vue
Normal file
@ -0,0 +1,332 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-button
|
||||
:disabled="!('applyTungstenFabricPolicy' in $store.getters.apis)"
|
||||
type="dashed"
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="onShowAction">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.apply.tungsten.network.policy') }}
|
||||
</a-button>
|
||||
<a-table
|
||||
size="small"
|
||||
:loading="fetchLoading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="(item, index) => index"
|
||||
:pagination="false">
|
||||
<template #action="{ record }">
|
||||
<a-popconfirm
|
||||
v-if="'removeTungstenFabricPolicy' in $store.getters.apis"
|
||||
placement="topRight"
|
||||
:title="$t('message.confirm.remove.network.policy')"
|
||||
:ok-text="$t('label.yes')"
|
||||
:cancel-text="$t('label.no')"
|
||||
:loading="deleteLoading"
|
||||
@confirm="removeNetworkPolicy(record)"
|
||||
>
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.action.remove.network.policy')"
|
||||
danger
|
||||
type="primary"
|
||||
icon="delete-outlined" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
<div style="display: block; text-align: right; margin-top: 10px;">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="itemCount"
|
||||
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="pageSizeOptions"
|
||||
@change="changePage"
|
||||
@showSizeChange="changePageSize"
|
||||
showSizeChanger>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
<a-modal
|
||||
v-if="showAction"
|
||||
:visible="showAction"
|
||||
:title="$t('label.apply.tungsten.network.policy')"
|
||||
:maskClosable="false"
|
||||
:footer="null"
|
||||
@cancel="showAction = false">
|
||||
<div v-ctrl-enter="handleSubmit">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical">
|
||||
<a-form-item name="policyuuid" ref="policyuuid">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.policyuuid')" :tooltip="apiParams.policyuuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
:loading="networks.loading"
|
||||
:placeholder="apiParams.policyuuid.description"
|
||||
v-model:value="form.policyuuid">
|
||||
<a-select-option v-for="network in networks.opts" :key="network.uuid">{{ network.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="majorsequence" ref="majorsequence">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.majorsequence')" :tooltip="apiParams.majorsequence.description"/>
|
||||
</template>
|
||||
<a-input v-model:value="form.majorsequence" :placeholder="apiParams.majorsequence.description" />
|
||||
</a-form-item>
|
||||
<a-form-item name="minorsequence" ref="minorsequence">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.minorsequence')" :tooltip="apiParams.minorsequence.description"/>
|
||||
</template>
|
||||
<a-input v-model:value="form.minorsequence" :placeholder="apiParams.minorsequence.description" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="() => { showAction = false }">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button type="primary" ref="submit" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import { mixinDevice } from '@/utils/mixin.js'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'NetworkPolicyTab',
|
||||
components: { TooltipButton, TooltipLabel },
|
||||
mixins: [mixinDevice],
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
fetchLoading: false,
|
||||
deleteLoading: false,
|
||||
submitLoading: false,
|
||||
showAction: false,
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
itemCount: 0,
|
||||
columns: [{
|
||||
title: this.$t('label.name'),
|
||||
dataIndex: 'name'
|
||||
}, {
|
||||
title: this.$t('label.action'),
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
width: 80
|
||||
}],
|
||||
dataSource: [],
|
||||
networks: {
|
||||
loading: false,
|
||||
opts: []
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource (newData, oldData) {
|
||||
if (newData !== oldData) {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('applyTungstenFabricPolicy')
|
||||
},
|
||||
created () {
|
||||
this.fetchData()
|
||||
},
|
||||
computed: {
|
||||
pageSizeOptions () {
|
||||
const sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
|
||||
if (this.device !== 'desktop') {
|
||||
sizes.unshift(10)
|
||||
}
|
||||
return [...new Set(sizes)].sort(function (a, b) {
|
||||
return a - b
|
||||
}).map(String)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({
|
||||
majorsequence: 0,
|
||||
minorsequence: 0
|
||||
})
|
||||
this.rules = reactive({
|
||||
policyuuid: [{ required: true, message: this.$t('message.error.select') }],
|
||||
majorsequence: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
minorsequence: [{ required: true, message: this.$t('message.error.required.input') }]
|
||||
})
|
||||
},
|
||||
initRemoveForm () {
|
||||
this.removeRef = ref()
|
||||
this.removeForm = reactive({
|
||||
policyuuid: this.networks.opts[0]?.uuid || null
|
||||
})
|
||||
this.removeRules = reactive({
|
||||
policyuuid: [{ required: true, message: this.$t('message.error.select') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (Object.keys(this.resource).length === 0) {
|
||||
return
|
||||
}
|
||||
const params = {}
|
||||
params.zoneid = this.resource.zoneid
|
||||
params.networkid = this.resource.id
|
||||
params.listAll = true
|
||||
params.page = this.page
|
||||
params.pagesize = this.pageSize
|
||||
|
||||
this.itemCount = 0
|
||||
this.dataSource = []
|
||||
this.fetchLoading = true
|
||||
|
||||
api('listTungstenFabricPolicy', params).then(json => {
|
||||
this.itemCount = json?.listtungstenfabricpolicyresponse?.count || 0
|
||||
this.dataSource = json?.listtungstenfabricpolicyresponse?.policy || []
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.fetchLoading = false })
|
||||
},
|
||||
onShowAction () {
|
||||
this.initForm()
|
||||
this.showAction = true
|
||||
this.networks.loading = true
|
||||
this.networks.opts = []
|
||||
api('listTungstenFabricPolicy', { listall: true, zoneid: this.resource.zoneid }).then(json => {
|
||||
this.networks.opts = json?.listtungstenfabricpolicyresponse?.policy || []
|
||||
this.form.networkuuid = this.networks.opts[0]?.uuid || null
|
||||
}).finally(() => {
|
||||
this.networks.loading = false
|
||||
})
|
||||
},
|
||||
changePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
changePageSize (currentPage, pageSize) {
|
||||
this.page = currentPage
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
handleSubmit () {
|
||||
if (this.submitLoading) return
|
||||
this.submitLoading = true
|
||||
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
|
||||
const params = {}
|
||||
params.zoneid = this.resource.zoneid
|
||||
params.networkuuid = this.resource.id
|
||||
params.policyuuid = values.policyuuid
|
||||
params.majorsequence = values.majorsequence
|
||||
params.minorsequence = values.minorsequence
|
||||
|
||||
const match = this.networks.opts.filter(network => network.uuid === values.policyuuid)
|
||||
const resourceName = match[0]?.name || values.policyuuid
|
||||
|
||||
api('applyTungstenFabricPolicy', params).then(json => {
|
||||
const jobId = json?.applytungstenfabricpolicyresponse?.jobid
|
||||
this.$pollJob({
|
||||
jobId,
|
||||
title: this.$t('label.apply.tungsten.network.policy'),
|
||||
description: resourceName,
|
||||
successMessage: this.$t('message.success.apply.network.policy'),
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
errorMessage: this.$t('message.error.apply.network.policy'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.showAction = false
|
||||
this.submitLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.submitLoading = false
|
||||
})
|
||||
},
|
||||
removeNetworkPolicy (record) {
|
||||
if (this.deleteLoading) return
|
||||
this.deleteLoading = true
|
||||
const params = {}
|
||||
params.zoneid = this.resource.zoneid
|
||||
params.networkuuid = this.resource.id
|
||||
params.policyuuid = record.uuid
|
||||
|
||||
api('removeTungstenFabricPolicy', params).then(json => {
|
||||
const jobId = json?.removetungstenfabricpolicyresponse?.jobid
|
||||
this.$pollJob({
|
||||
jobId,
|
||||
title: this.$t('label.action.remove.network.policy'),
|
||||
description: record.name || record.uuid,
|
||||
successMessage: this.$t('message.success.remove.network.policy'),
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
errorMessage: this.$t('message.error.remove.network.policy'),
|
||||
errorMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.deleteLoading = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
505
ui/src/views/network/tungsten/TungstenFabric.vue
Normal file
505
ui/src/views/network/tungsten/TungstenFabric.vue
Normal file
@ -0,0 +1,505 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-tabs tab-position="left">
|
||||
<a-tab-pane
|
||||
v-for="tab in tabs"
|
||||
:key="tab.name"
|
||||
:tab="$t('label.' + tab.name)">
|
||||
<tungsten-fabric-table-view
|
||||
:apiName="tab.api"
|
||||
:actions="tab.actions"
|
||||
:columns="tab.columns"
|
||||
:resource="resource"
|
||||
:loading="loading"
|
||||
:tab="tab.name" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TungstenFabricTableView from '@/views/network/tungsten/TungstenFabricTableView'
|
||||
|
||||
export default {
|
||||
name: 'TungstenFabric',
|
||||
components: { TungstenFabricTableView },
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabs: [
|
||||
{
|
||||
name: 'network.policy',
|
||||
api: 'listTungstenFabricPolicy',
|
||||
actions: [
|
||||
{
|
||||
api: 'createTungstenFabricPolicy',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.tungsten.policy',
|
||||
dataView: false,
|
||||
listView: true,
|
||||
popup: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
api: 'deleteTungstenFabricPolicy',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.policy',
|
||||
dataView: true,
|
||||
confirm: true,
|
||||
message: 'label.confirm.delete.tungsten.policy',
|
||||
args: {
|
||||
policyuuid: (record) => record.uuid
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'network',
|
||||
title: this.$t('label.network'),
|
||||
slots: { customRender: 'network' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 150
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'application.policy.set',
|
||||
api: 'listTungstenFabricApplicationPolicySet',
|
||||
actions: [
|
||||
{
|
||||
api: 'createTungstenFabricApplicationPolicySet',
|
||||
label: 'label.add.tungsten.policy.set',
|
||||
icon: 'plus-outlined',
|
||||
dataView: false,
|
||||
listView: true,
|
||||
popup: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
api: 'deleteTungstenFabricApplicationPolicySet',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.policy.set',
|
||||
dataView: true,
|
||||
confirm: true,
|
||||
message: 'label.confirm.delete.tungsten.policy.set',
|
||||
args: {
|
||||
applicationpolicysetuuid: (record) => record.uuid
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'firewallpolicy',
|
||||
title: this.$t('label.firewallpolicy'),
|
||||
slots: { customRender: 'firewallpolicy' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'tag',
|
||||
title: this.$t('label.tag'),
|
||||
slots: { customRender: 'tag' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 150
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'tungsten.logical.router',
|
||||
api: 'listTungstenFabricLogicalRouter',
|
||||
actions: [
|
||||
{
|
||||
api: 'createTungstenFabricLogicalRouter',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.tungsten.logical.route',
|
||||
listView: true,
|
||||
popup: true,
|
||||
fields: [{
|
||||
name: 'name',
|
||||
required: true
|
||||
}]
|
||||
},
|
||||
{
|
||||
api: 'removeTungstenFabricNetworkGatewayFromLogicalRouter',
|
||||
icon: 'close-outlined',
|
||||
label: 'label.remove.logical.network',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
fields: [
|
||||
{
|
||||
label: 'label.network',
|
||||
name: 'networkuuid',
|
||||
required: true,
|
||||
type: 'uuid',
|
||||
loading: false,
|
||||
opts: [],
|
||||
optGet: record => record.network
|
||||
}
|
||||
],
|
||||
show: record => record.network.length > 0,
|
||||
args: {
|
||||
logicalrouteruuid: record => record.uuid
|
||||
}
|
||||
},
|
||||
{
|
||||
api: 'deleteTungstenFabricLogicalRouter',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.logical.router',
|
||||
dataView: true,
|
||||
confirm: true,
|
||||
message: 'label.confirm.remove.logical.router',
|
||||
args: {
|
||||
logicalrouteruuid: record => record.uuid
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
slots: { customRender: 'name' }
|
||||
}, {
|
||||
dataIndex: 'network',
|
||||
title: this.$t('label.network'),
|
||||
slots: { customRender: 'network' }
|
||||
}, {
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 150
|
||||
}]
|
||||
},
|
||||
{
|
||||
name: 'tag',
|
||||
api: 'listTungstenFabricTag',
|
||||
actions: [
|
||||
{
|
||||
api: 'createTungstenFabricTag',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.tungsten.tag',
|
||||
dataView: false,
|
||||
listView: true,
|
||||
popup: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'tagtype',
|
||||
label: 'label.tag.type',
|
||||
required: true,
|
||||
type: 'uuid',
|
||||
api: 'listTungstenFabricTagType',
|
||||
loading: false,
|
||||
opts: []
|
||||
},
|
||||
{
|
||||
name: 'tagvalue',
|
||||
label: 'label.tag.value',
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
api: 'removeTungstenFabricTag',
|
||||
icon: 'close-outlined',
|
||||
label: 'label.remove.tungsten.tag',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'networkuuid',
|
||||
type: 'uuid',
|
||||
multiple: true,
|
||||
loading: false,
|
||||
opts: [],
|
||||
optGet: record => record.network
|
||||
},
|
||||
{
|
||||
name: 'vmuuid',
|
||||
type: 'uuid',
|
||||
multiple: true,
|
||||
loading: false,
|
||||
opts: [],
|
||||
optGet: record => record.vm
|
||||
},
|
||||
{
|
||||
name: 'nicuuid',
|
||||
type: 'uuid',
|
||||
multiple: true,
|
||||
loading: false,
|
||||
opts: [],
|
||||
optGet: record => record.nic
|
||||
}
|
||||
],
|
||||
show: record => record.network.length > 0 || record.vm.length > 0 || record.nic.length > 0,
|
||||
args: {
|
||||
taguuid: (record) => record.uuid
|
||||
}
|
||||
},
|
||||
{
|
||||
api: 'deleteTungstenFabricTag',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.fabric.tag',
|
||||
dataView: true,
|
||||
confirm: true,
|
||||
message: 'label.confirm.delete.tungsten.tag',
|
||||
args: {
|
||||
taguuid: (record) => record.uuid
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 150
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'tag.type',
|
||||
api: 'listTungstenFabricTagType',
|
||||
actions: [
|
||||
{
|
||||
api: 'createTungstenFabricTagType',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.tungsten.tag.type',
|
||||
dataView: false,
|
||||
listView: true,
|
||||
popup: true,
|
||||
fields: [{
|
||||
name: 'name',
|
||||
required: true
|
||||
}]
|
||||
},
|
||||
{
|
||||
api: 'deleteTungstenFabricTagType',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.fabric.tag.type',
|
||||
dataView: true,
|
||||
confirm: true,
|
||||
message: 'label.confirm.delete.tungsten.tag.type',
|
||||
args: {
|
||||
tagtypeuuid: (record) => record.uuid
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
slots: { customRender: 'name' }
|
||||
}, {
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 150
|
||||
}]
|
||||
},
|
||||
{
|
||||
name: 'service.group',
|
||||
api: 'listTungstenFabricServiceGroup',
|
||||
actions: [
|
||||
{
|
||||
api: 'createTungstenFabricServiceGroup',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.tungsten.service.group',
|
||||
dataView: false,
|
||||
listView: true,
|
||||
popup: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'protocol',
|
||||
required: true,
|
||||
type: 'uuid',
|
||||
loading: false,
|
||||
optGet: (record) => {
|
||||
return [{
|
||||
uuid: 'any',
|
||||
name: 'ANY'
|
||||
}, {
|
||||
uuid: 'tcp',
|
||||
name: 'TCP'
|
||||
}, {
|
||||
uuid: 'udp',
|
||||
name: 'UDP'
|
||||
}, {
|
||||
uuid: 'icmp',
|
||||
name: 'ICMP'
|
||||
}]
|
||||
},
|
||||
value: 'any'
|
||||
},
|
||||
{
|
||||
name: 'startport',
|
||||
required: true,
|
||||
value: '-1'
|
||||
},
|
||||
{
|
||||
name: 'endport',
|
||||
required: true,
|
||||
value: '-1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
api: 'deleteTungstenFabricServiceGroup',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.service.group',
|
||||
dataView: true,
|
||||
confirm: true,
|
||||
message: 'label.confirm.delete.tungsten.service.group',
|
||||
args: {
|
||||
servicegroupuuid: record => record.uuid
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'protocol',
|
||||
title: this.$t('label.protocol'),
|
||||
slots: { customRender: 'protocol' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'startport',
|
||||
title: this.$t('label.startport'),
|
||||
slots: { customRender: 'startport' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'endport',
|
||||
title: this.$t('label.endport'),
|
||||
slots: { customRender: 'endport' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 150
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'address.group',
|
||||
api: 'listTungstenFabricAddressGroup',
|
||||
actions: [
|
||||
{
|
||||
api: 'createTungstenFabricAddressGroup',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.tungsten.address.group',
|
||||
listView: true,
|
||||
popup: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'ipprefix',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'ipprefixlen',
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
api: 'deleteTungstenFabricAddressGroup',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.tungsten.address.group',
|
||||
dataView: true,
|
||||
confirm: true,
|
||||
message: 'label.confirm.delete.tungsten.address.group',
|
||||
args: {
|
||||
addressgroupuuid: record => record.uuid
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'ipprefix',
|
||||
title: this.$t('label.ipprefix'),
|
||||
slots: { customRender: 'ipprefix' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'ipprefixlen',
|
||||
title: this.$t('label.ipprefixlen'),
|
||||
slots: { customRender: 'ipprefixlen' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.action'),
|
||||
slots: { customRender: 'action' },
|
||||
width: 150
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
468
ui/src/views/network/tungsten/TungstenFabricPolicyRule.vue
Normal file
468
ui/src/views/network/tungsten/TungstenFabricPolicyRule.vue
Normal file
@ -0,0 +1,468 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-button
|
||||
:disabled="!('addTungstenFabricPolicyRule' in $store.getters.apis)"
|
||||
type="dashed"
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="onShowAction">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.add.rule') }}
|
||||
</a-button>
|
||||
<a-table
|
||||
size="small"
|
||||
:loading="loading || fetchLoading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="(item, index) => index"
|
||||
:pagination="false">
|
||||
<template #sourceport="{ record }">
|
||||
<span>{{ record.srcstartport + ':' + record.srcendport }}</span>
|
||||
</template>
|
||||
<template #destport="{ record }">
|
||||
<span>{{ record.deststartport + ':' + record.destendport }}</span>
|
||||
</template>
|
||||
<template #ruleAction="{ record }">
|
||||
<a-popconfirm
|
||||
v-if="'removeTungstenFabricPolicyRule' in $store.getters.apis"
|
||||
placement="topRight"
|
||||
:title="$t('message.delete.tungsten.policy.rule')"
|
||||
:ok-text="$t('label.yes')"
|
||||
:cancel-text="$t('label.no')"
|
||||
:loading="deleteLoading"
|
||||
@confirm="deleteRule(record)"
|
||||
>
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.delete.rule')"
|
||||
danger
|
||||
type="primary"
|
||||
icon="delete-outlined" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div style="display: block; text-align: right; margin-top: 10px;">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="itemCount"
|
||||
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="pageSizeOptions"
|
||||
@change="onChangePage"
|
||||
@showSizeChange="onChangePageSize"
|
||||
showSizeChanger>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
|
||||
<a-modal
|
||||
v-if="showAction"
|
||||
:visible="showAction"
|
||||
:title="$t('label.add.rule')"
|
||||
:maskClosable="false"
|
||||
:footer="null"
|
||||
@cancel="showAction = false">
|
||||
<div v-ctrl-enter="handleSubmit">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical">
|
||||
<a-form-item name="action" ref="action">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.action')" :tooltip="apiParams.action.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-focus="true"
|
||||
v-model:value="form.action"
|
||||
:placeholder="apiParams.action.description">
|
||||
<a-select-option value="pass">PASS</a-select-option>
|
||||
<a-select-option value="deny">DENY</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="direction" ref="direction">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.direction')" :tooltip="apiParams.direction.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.direction"
|
||||
:placeholder="apiParams.direction.description">
|
||||
<a-select-option value="oneway">ONE WAY</a-select-option>
|
||||
<a-select-option value="twoway">TWO WAY</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="protocol" ref="protocol">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.protocol')" :tooltip="apiParams.protocol.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.protocol"
|
||||
:placeholder="apiParams.protocol.description">
|
||||
<a-select-option value="tcp">TCP</a-select-option>
|
||||
<a-select-option value="udp">UDP</a-select-option>
|
||||
<a-select-option value="icmp">ICMP</a-select-option>
|
||||
<a-select-option value="any">ANY</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="srcnetwork" ref="srcnetwork">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srcnetwork')" :tooltip="apiParams.srcnetwork.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.srcnetwork"
|
||||
:placeholder="apiParams.srcnetwork.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="srcipprefix" ref="srcipprefix">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srcipprefix')" :tooltip="apiParams.srcnetwork.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.srcipprefix"
|
||||
:placeholder="apiParams.srcipprefix.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="srcipprefixlen" ref="srcipprefixlen">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srcipprefixlen')" :tooltip="apiParams.srcipprefixlen.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.srcipprefixlen"
|
||||
:placeholder="apiParams.srcipprefixlen.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="srcstartport" ref="srcstartport">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srcstartport')" :tooltip="apiParams.srcstartport.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.srcstartport"
|
||||
:placeholder="apiParams.srcstartport.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="srcendport" ref="srcendport">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.srcendport')" :tooltip="apiParams.srcendport.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.srcendport"
|
||||
:placeholder="apiParams.srcendport.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="destnetwork" ref="destnetwork">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.destnetwork')" :tooltip="apiParams.destnetwork.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.destnetwork"
|
||||
:placeholder="apiParams.destnetwork.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="destipprefix" ref="destipprefix">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.destipprefix')" :tooltip="apiParams.destipprefix.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.destipprefix"
|
||||
:placeholder="apiParams.destipprefix.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="destipprefixlen" ref="destipprefixlen">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.destipprefixlen')" :tooltip="apiParams.destipprefixlen.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.destipprefixlen"
|
||||
:placeholder="apiParams.destipprefixlen.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="deststartport" ref="deststartport">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.deststartport')" :tooltip="apiParams.deststartport.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.deststartport"
|
||||
:placeholder="apiParams.deststartport.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="destendport" ref="destendport">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.destendport')" :tooltip="apiParams.destendport.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.destendport"
|
||||
:placeholder="apiParams.destendport.description"/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button :loading="actionLoading" @click="() => { showAction = false }">{{ this.$t('label.cancel') }}</a-button>
|
||||
<a-button :loading="actionLoading" type="primary" ref="submit" @click="handleSubmit">{{ this.$t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import { mixinDevice } from '@/utils/mixin.js'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'TungstenFabricPolicyRule',
|
||||
components: {
|
||||
TooltipButton,
|
||||
TooltipLabel
|
||||
},
|
||||
mixins: [mixinDevice],
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showAction: false,
|
||||
zoneId: null,
|
||||
fetchLoading: false,
|
||||
actionLoading: false,
|
||||
deleteLoading: false,
|
||||
dataSource: [],
|
||||
itemCount: 0,
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
columns: [
|
||||
{
|
||||
title: this.$t('label.action'),
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.direction'),
|
||||
dataIndex: 'direction',
|
||||
slots: { customRender: 'direction' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.protocol'),
|
||||
dataIndex: 'protocol',
|
||||
slots: { customRender: 'protocol' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.srcnetwork'),
|
||||
dataIndex: 'srcnetwork',
|
||||
slots: { customRender: 'srcnetwork' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.sourceport'),
|
||||
dataIndex: 'sourceport',
|
||||
slots: { customRender: 'sourceport' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.destnetwork'),
|
||||
dataIndex: 'destnetwork',
|
||||
slots: { customRender: 'destnetwork' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.destport'),
|
||||
dataIndex: 'destport',
|
||||
slots: { customRender: 'destport' }
|
||||
},
|
||||
{
|
||||
dataIndex: 'ruleAction',
|
||||
slots: { customRender: 'ruleAction' },
|
||||
width: 50
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pageSizeOptions () {
|
||||
const sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
|
||||
if (this.device !== 'desktop') {
|
||||
sizes.unshift(10)
|
||||
}
|
||||
return [...new Set(sizes)].sort(function (a, b) {
|
||||
return a - b
|
||||
}).map(String)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('addTungstenFabricPolicyRule')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({
|
||||
action: 'pass',
|
||||
direction: 'oneway',
|
||||
protocol: 'tcp',
|
||||
srcnetwork: 'any',
|
||||
srcipprefix: '0.0.0.0',
|
||||
srcipprefixlen: '0',
|
||||
srcstartport: '-1',
|
||||
srcendport: '-1',
|
||||
destnetwork: 'any',
|
||||
destipprefix: '0.0.0.0',
|
||||
destipprefixlen: '0',
|
||||
deststartport: '-1',
|
||||
destendport: '-1'
|
||||
})
|
||||
this.rules = reactive({
|
||||
action: [{ required: true, message: this.$t('message.error.select') }],
|
||||
direction: [{ required: true, message: this.$t('message.error.select') }],
|
||||
protocol: [{ required: true, message: this.$t('message.error.select') }],
|
||||
srcnetwork: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
srcipprefix: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
srcipprefixlen: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
srcstartport: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
srcendport: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
destnetwork: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
destipprefix: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
destipprefixlen: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
deststartport: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
destendport: [{ required: true, message: this.$t('message.error.required.input') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (!this.resource.uuid || !('zoneid' in this.$route.query)) {
|
||||
return
|
||||
}
|
||||
this.zoneId = this.$route.query.zoneid
|
||||
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.policyuuid = this.resource.uuid
|
||||
|
||||
this.dataSource = []
|
||||
this.fetchLoading = true
|
||||
api('listTungstenFabricPolicyRule', params).then(json => {
|
||||
this.dataSource = json?.listtungstenfabricpolicyruleresponse?.rule || []
|
||||
this.itemCount = json?.listtungstenfabricpolicyruleresponse?.count || 0
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.fetchLoading = false })
|
||||
},
|
||||
onShowAction () {
|
||||
this.showAction = true
|
||||
},
|
||||
handleSubmit () {
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.policyuuid = this.resource.uuid
|
||||
params.action = values.action
|
||||
params.direction = values.direction
|
||||
params.protocol = values.protocol
|
||||
params.srcnetwork = values.srcnetwork
|
||||
params.srcipprefix = values.srcipprefix
|
||||
params.srcipprefixlen = values.srcipprefixlen
|
||||
params.srcstartport = values.srcstartport
|
||||
params.srcendport = values.srcendport
|
||||
params.destnetwork = values.destnetwork
|
||||
params.destipprefix = values.destipprefix
|
||||
params.destipprefixlen = values.destipprefixlen
|
||||
params.deststartport = values.deststartport
|
||||
params.destendport = values.destendport
|
||||
|
||||
this.actionLoading = true
|
||||
api('addTungstenFabricPolicyRule', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.addtungstenfabricpolicyruleresponse.jobid,
|
||||
title: this.$t('label.add.rule'),
|
||||
successMessage: `${this.$t('message.success.add.policy.rule')}`,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
errorMessage: this.$t('message.error.add.policy.rule'),
|
||||
loadingMessage: this.$t('message.loading.add.policy.rule'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.showAction = false
|
||||
this.actionLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.actionLoading = false
|
||||
})
|
||||
},
|
||||
deleteRule (record) {
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.policyuuid = this.resource.uuid
|
||||
params.ruleuuid = record.uuid
|
||||
|
||||
this.deleteLoading = true
|
||||
api('removeTungstenFabricPolicyRule', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.removetungstenfabricpolicyruleresponse.jobid,
|
||||
title: this.$t('label.delete.rule'),
|
||||
description: record.uuid,
|
||||
successMessage: `${this.$t('message.success.delete.tungsten.policy.rule')} ${record.uuid}`,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
errorMessage: this.$t('message.error.delete.tungsten.policy.rule'),
|
||||
loadingMessage: this.$t('message.loading.delete.tungsten.policy.rule'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.deleteLoading = false })
|
||||
},
|
||||
onChangePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
onChangePageSize (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
320
ui/src/views/network/tungsten/TungstenFabricPolicyTag.vue
Normal file
320
ui/src/views/network/tungsten/TungstenFabricPolicyTag.vue
Normal file
@ -0,0 +1,320 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-button
|
||||
:disabled="!('applyTungstenFabricTag' in $store.getters.apis)"
|
||||
type="dashed"
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="onShowAction">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.apply.tungsten.tag') }}
|
||||
</a-button>
|
||||
<a-table
|
||||
size="small"
|
||||
:loading="fetchLoading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="(item, index) => index"
|
||||
:pagination="false">
|
||||
<template #policy="{ record }">
|
||||
<span v-if="record.policy.length > 0">{{ record.policy[0].name }}</span>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<a-popconfirm
|
||||
v-if="'removeTungstenFabricTag' in $store.getters.apis"
|
||||
placement="topRight"
|
||||
:title="$t('message.delete.tungsten.tag')"
|
||||
:ok-text="$t('label.yes')"
|
||||
:cancel-text="$t('label.no')"
|
||||
:loading="deleteLoading"
|
||||
@confirm="deleteRule(record)"
|
||||
>
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.delete.tag')"
|
||||
danger
|
||||
type="primary"
|
||||
icon="delete-outlined" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div style="display: block; text-align: right; margin-top: 10px;">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="itemCount"
|
||||
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="pageSizeOptions"
|
||||
@change="onChangePage"
|
||||
@showSizeChange="onChangePageSize"
|
||||
showSizeChanger>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
|
||||
<a-modal
|
||||
v-if="showAction"
|
||||
:visible="showAction"
|
||||
:title="$t('label.apply.tungsten.tag')"
|
||||
:maskClosable="false"
|
||||
:footer="null"
|
||||
@cancel="showAction = false">
|
||||
<div v-ctrl-enter="handleSubmit">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical">
|
||||
<a-form-item name="taguuid" ref="taguuid">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.taguuid')" :tooltip="apiParams.taguuid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-focus="true"
|
||||
:loading="tags.loading"
|
||||
v-model:value="form.taguuid"
|
||||
:placeholder="apiParams.taguuid.description">
|
||||
<a-select-option v-for="item in tags.opts" :key="item.uuid">{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button :loading="actionLoading" @click="() => { showAction = false }">{{ this.$t('label.cancel') }}</a-button>
|
||||
<a-button :loading="actionLoading" type="primary" ref="submit" @click="handleSubmit">{{ this.$t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import { mixinDevice } from '@/utils/mixin.js'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'TungstenFabricPolicyTag',
|
||||
components: {
|
||||
TooltipButton,
|
||||
TooltipLabel
|
||||
},
|
||||
mixins: [mixinDevice],
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showAction: false,
|
||||
tagSelected: null,
|
||||
tags: {
|
||||
loading: false,
|
||||
opts: []
|
||||
},
|
||||
zoneId: null,
|
||||
fetchLoading: false,
|
||||
actionLoading: false,
|
||||
deleteLoading: false,
|
||||
dataSource: [],
|
||||
itemCount: 0,
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
columns: [
|
||||
{
|
||||
title: this.$t('label.name'),
|
||||
dataIndex: 'name',
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.policy'),
|
||||
dataIndex: 'policy',
|
||||
slots: { customRender: 'policy' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.action'),
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
width: 70
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pageSizeOptions () {
|
||||
const sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
|
||||
if (this.device !== 'desktop') {
|
||||
sizes.unshift(10)
|
||||
}
|
||||
return [...new Set(sizes)].sort(function (a, b) {
|
||||
return a - b
|
||||
}).map(String)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('applyTungstenFabricTag')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({
|
||||
taguuid: [{ required: true, message: this.$t('message.error.select') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (!this.resource.uuid || !('zoneid' in this.$route.query)) {
|
||||
return
|
||||
}
|
||||
this.zoneId = this.$route.query.zoneid
|
||||
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.policyuuid = this.resource.uuid
|
||||
|
||||
this.fetchLoading = true
|
||||
api('listTungstenFabricTag', params).then(json => {
|
||||
this.dataSource = json?.listtungstenfabrictagresponse?.tag || []
|
||||
this.itemCount = json?.listtungstenfabrictagresponse?.count || 0
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.fetchLoading = false })
|
||||
},
|
||||
onShowAction () {
|
||||
this.showAction = true
|
||||
|
||||
this.tags.loading = true
|
||||
this.tags.opts = []
|
||||
api('listTungstenFabricTag', { zoneid: this.zoneId }).then(json => {
|
||||
const listTags = json?.listtungstenfabrictagresponse?.tag || []
|
||||
|
||||
this.tags.opts = listTags.filter(item => {
|
||||
const tagExist = this.dataSource.findIndex(tag => tag.uuid === item.uuid)
|
||||
return tagExist === -1
|
||||
})
|
||||
|
||||
this.tagSelected = this.tags.opts[0]?.uuid || null
|
||||
}).finally(() => { this.tags.loading = false })
|
||||
},
|
||||
handleSubmit () {
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.policyuuid = this.resource.uuid
|
||||
params.taguuid = values.taguuid
|
||||
|
||||
const tag = this.tags.opts.filter(item => item.uuid === values.taguuid)
|
||||
const description = tag.length > 0 ? tag[0].name : values.taguuid
|
||||
|
||||
this.actionLoading = true
|
||||
api('applyTungstenFabricTag', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.applytungstenfabrictagresponse.jobid,
|
||||
title: this.$t('label.apply.tungsten.tag'),
|
||||
description: description,
|
||||
successMessage: `${this.$t('message.success.apply.tungsten.tag')}`,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
errorMessage: this.$t('message.error.apply.tungsten.tag'),
|
||||
loadingMessage: this.$t('message.loading.apply.tungsten.tag'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.showAction = false
|
||||
this.actionLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
}).finally(() => {
|
||||
this.actionLoading = false
|
||||
})
|
||||
},
|
||||
deleteRule (record) {
|
||||
const params = {}
|
||||
params.zoneid = this.zoneId
|
||||
params.policyuuid = this.resource.uuid
|
||||
params.taguuid = record.uuid
|
||||
|
||||
this.deleteLoading = true
|
||||
api('removeTungstenFabricTag', params).then(json => {
|
||||
this.$pollJob({
|
||||
jobId: json.removetungstenfabrictagresponse.jobid,
|
||||
title: this.$t('label.delete.rule'),
|
||||
description: record.name || record.uuid,
|
||||
successMessage: `${this.$t('message.success.delete.tungsten.tag')} ${record.name || record.uuid}`,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
errorMessage: this.$t('message.error.delete.tungsten.tag'),
|
||||
loadingMessage: this.$t('message.loading.delete.tungsten.tag'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => { this.deleteLoading = false })
|
||||
},
|
||||
onChangePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
onChangePageSize (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
456
ui/src/views/network/tungsten/TungstenFabricTableView.vue
Normal file
456
ui/src/views/network/tungsten/TungstenFabricTableView.vue
Normal file
@ -0,0 +1,456 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<tungsten-network-action
|
||||
:actions="listAction"
|
||||
:page="page"
|
||||
:pageSize="pageSize" />
|
||||
<tungsten-network-table
|
||||
:apiName="apiName"
|
||||
:loading="loading || fetchLoading"
|
||||
:resource="resource"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:searchQuery="searchQuery"
|
||||
:page="page"
|
||||
:page-size="pageSize"
|
||||
:item-count="itemCount"
|
||||
:actions="detailAction"/>
|
||||
<div v-if="showAddModal">
|
||||
<keep-alive v-if="currentAction.component">
|
||||
<a-modal
|
||||
:visible="showAddModal"
|
||||
:closable="true"
|
||||
:maskClosable="false"
|
||||
style="top: 20px;"
|
||||
@cancel="closeAction"
|
||||
:confirmLoading="fetchLoading"
|
||||
:footer="null"
|
||||
centered
|
||||
width="auto"
|
||||
>
|
||||
<template #title>
|
||||
{{ $t(currentAction.title || currentAction.label) }}
|
||||
</template>
|
||||
<component
|
||||
:is="currentAction.component"
|
||||
:resource="resource"
|
||||
:loading="loading"
|
||||
:action="{currentAction}"
|
||||
v-bind="{currentAction}"
|
||||
@close-action="closeAction" />
|
||||
</a-modal>
|
||||
</keep-alive>
|
||||
<a-modal
|
||||
v-else
|
||||
:closable="true"
|
||||
:maskClosable="false"
|
||||
style="top: 20px;"
|
||||
:visible="showAddModal"
|
||||
:confirm-loading="fetchLoading"
|
||||
:footer="null"
|
||||
centered
|
||||
width="auto"
|
||||
@cancel="closeAction">
|
||||
<template #title>
|
||||
{{ $t(currentAction.label) }}
|
||||
</template>
|
||||
<div v-ctrl-enter="handleSubmit">
|
||||
<a-form :ref="formRef" :model="form" :rules="rules" layout="vertical" class="form-layout">
|
||||
<div v-for="(field, index) in currentAction.fields" :key="field.name">
|
||||
<a-form-item
|
||||
:name="field.name"
|
||||
:ref="field.name"
|
||||
v-if="!currentAction.mapping || !field.name in currentAction.mapping">
|
||||
<template #label>
|
||||
<tooltip-label
|
||||
:title="'label' in field ? $t(field.label) : $t('label.' + field.name)"
|
||||
:tooltip="apiParams[field.name].description" />
|
||||
</template>
|
||||
<a-select
|
||||
v-if="field.type==='uuid'"
|
||||
v-focus="index === 0"
|
||||
:mode="field.multiple ? 'multiple' : null"
|
||||
v-model:value="form[field.name]"
|
||||
:loading="field.loading"
|
||||
:placeholder="apiParams[field.name].description"
|
||||
@change="(value) => handleChangeUuid(field.name, field.opts, value)">
|
||||
<a-select-option v-for="opt in field.opts" :key="opt.uuid || opt.id || opt.name">
|
||||
{{ opt.name || opt.displayName || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input-number
|
||||
style="width: 100%"
|
||||
v-else-if="field.type === 'number'"
|
||||
v-focus="index === 0"
|
||||
v-model:value="form[field.name]"
|
||||
:placeholder="apiParams[field.name].description"/>
|
||||
<a-input
|
||||
v-else
|
||||
v-focus="index === 0"
|
||||
v-model:value="form[field.name]"
|
||||
:placeholder="apiParams[field.name].description"/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button type="primary" @click="handleSubmit" ref="submit">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TungstenNetworkAction from '@/views/network/tungsten/TungstenNetworkAction'
|
||||
import TungstenNetworkTable from '@/views/network/tungsten/TungstenNetworkTable'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'TungstenFabricTableView',
|
||||
components: {
|
||||
TungstenNetworkAction,
|
||||
TungstenNetworkTable,
|
||||
TooltipLabel
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
apiName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
page: 1,
|
||||
pageSize: this.$store.getters.defaultListViewPageSize,
|
||||
itemCount: 0,
|
||||
searchQuery: '',
|
||||
dataSource: [],
|
||||
fetchLoading: false,
|
||||
showAddModal: false,
|
||||
currentAction: {},
|
||||
listAction: [],
|
||||
detailAction: [],
|
||||
tagType: ''
|
||||
}
|
||||
},
|
||||
provide: function () {
|
||||
return {
|
||||
onFetchData: this.fetchData,
|
||||
onExecAction: this.execAction
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.listAction = this.actions.filter(action => action.listView)
|
||||
this.detailAction = this.actions.filter(action => action.dataView)
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({})
|
||||
|
||||
if (!this.currentAction?.fields || this.currentAction.fields.length === 0) {
|
||||
return
|
||||
}
|
||||
this.currentAction.fields.forEach((field, index) => {
|
||||
this.form[field.name] = field?.value || null
|
||||
switch (field.type) {
|
||||
case 'uuid':
|
||||
if (field.multiple) this.form[field.name] = []
|
||||
this.rules[field.name] = [{ required: field.required, message: this.$t('message.error.select') }]
|
||||
break
|
||||
case 'number':
|
||||
this.rules[field.name] = [{ required: field.required, message: this.$t('message.error.required.input') }]
|
||||
break
|
||||
default:
|
||||
this.rules[field.name] = [{ required: field.required, message: this.$t('message.error.required.input') }]
|
||||
break
|
||||
}
|
||||
})
|
||||
},
|
||||
fetchData (args = {}) {
|
||||
if (!this.resource || !this.resource.zoneid) {
|
||||
return false
|
||||
}
|
||||
const params = {}
|
||||
if (Object.keys(args).length > 0) {
|
||||
this.page = args.page || 1
|
||||
this.pageSize = args.pageSize || 20
|
||||
this.searchQuery = args.searchQuery || ''
|
||||
}
|
||||
params.listAll = true
|
||||
params.page = this.page
|
||||
params.pagesize = this.pageSize
|
||||
params.keyword = this.searchQuery
|
||||
params.zoneid = this.resource.zoneid
|
||||
|
||||
this.itemCount = 0
|
||||
this.dataSource = []
|
||||
this.fetchLoading = true
|
||||
|
||||
api(this.apiName, params).then(json => {
|
||||
let responseName
|
||||
let objectName
|
||||
for (const key in json) {
|
||||
if (key.includes('response')) {
|
||||
responseName = key
|
||||
break
|
||||
}
|
||||
}
|
||||
for (const key in json[responseName]) {
|
||||
if (key === 'count') {
|
||||
this.itemCount = json[responseName].count
|
||||
continue
|
||||
}
|
||||
objectName = key
|
||||
break
|
||||
}
|
||||
this.dataSource = json[responseName][objectName] || []
|
||||
}).finally(() => {
|
||||
this.fetchLoading = false
|
||||
})
|
||||
},
|
||||
fetchOptions (record) {
|
||||
const uuidApiFields = this.currentAction.fields.filter(field => field.type === 'uuid' && field.api)
|
||||
const uuidFields = this.currentAction.fields.filter(field => field.type === 'uuid' && typeof field.optGet === 'function')
|
||||
if (uuidApiFields.length > 0) {
|
||||
uuidApiFields.forEach(field => {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
params.zoneid = this.resource.zoneid
|
||||
if (field.args) {
|
||||
for (const arg in field.args) {
|
||||
if (typeof field.args[arg] === 'function') {
|
||||
params[arg] = field.args[arg](record)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fieldIndex = this.currentAction.fields.findIndex(item => item.name === field.name)
|
||||
this.currentAction.fields[fieldIndex].loading = true
|
||||
|
||||
api(field.api, params).then(json => {
|
||||
let responseName
|
||||
let objectName
|
||||
for (const key in json) {
|
||||
if (key.includes('response')) {
|
||||
responseName = key
|
||||
break
|
||||
}
|
||||
}
|
||||
for (const key in json[responseName]) {
|
||||
if (key === 'count') {
|
||||
continue
|
||||
}
|
||||
objectName = key
|
||||
break
|
||||
}
|
||||
this.currentAction.fields[fieldIndex].opts = json[responseName][objectName] || []
|
||||
}).finally(() => {
|
||||
this.currentAction.fields[fieldIndex].loading = false
|
||||
})
|
||||
})
|
||||
}
|
||||
if (uuidFields.length > 0) {
|
||||
uuidFields.forEach(field => {
|
||||
const fieldIndex = this.currentAction.fields.findIndex(item => item.name === field.name)
|
||||
this.currentAction.fields[fieldIndex].opts = this.currentAction.fields[fieldIndex].optGet(record) || []
|
||||
})
|
||||
}
|
||||
},
|
||||
execAction (action, record) {
|
||||
this.currentAction = action
|
||||
this.currentAction.record = record
|
||||
this.initForm()
|
||||
if (this.currentAction.component) {
|
||||
this.showAddModal = true
|
||||
return
|
||||
}
|
||||
if (this.currentAction.popup) {
|
||||
this.fetchOptions(record)
|
||||
this.apiParams = this.$getApiParams(this.currentAction.api)
|
||||
this.showAddModal = true
|
||||
return
|
||||
}
|
||||
if (this.currentAction.confirm) {
|
||||
const self = this
|
||||
this.$confirm({
|
||||
title: this.$t(this.currentAction.message),
|
||||
okText: this.$t('label.ok'),
|
||||
okType: 'danger',
|
||||
cancelText: this.$t('label.cancel'),
|
||||
onOk () {
|
||||
self.onRemoveAction(record)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
|
||||
// this.fetchLoading = true
|
||||
const params = {}
|
||||
params.zoneid = this.resource.zoneid
|
||||
|
||||
for (const key in values) {
|
||||
let inputVal = values[key]
|
||||
if (Array.isArray(values[key])) {
|
||||
inputVal = values[key].join(',')
|
||||
}
|
||||
if (key === 'tagtype') {
|
||||
params[key] = this.tagType
|
||||
continue
|
||||
}
|
||||
params[key] = inputVal
|
||||
}
|
||||
if (this.currentAction.args) {
|
||||
for (const arg in this.currentAction.args) {
|
||||
if (typeof this.currentAction.args[arg] === 'function') {
|
||||
params[arg] = this.currentAction.args[arg](this.currentAction.record)
|
||||
}
|
||||
}
|
||||
}
|
||||
api(this.currentAction.api, params).then(json => {
|
||||
const jsonResponseName = [this.currentAction.api, 'response'].join('').toLowerCase()
|
||||
const jobId = json[jsonResponseName].jobid
|
||||
if (!jobId) {
|
||||
this.fetchData()
|
||||
return
|
||||
}
|
||||
|
||||
let resourceName = values.name
|
||||
if (this.currentAction.api === 'createTungstenFabricTag') {
|
||||
resourceName = [values.tagtype, values.tagvalue].join('=')
|
||||
}
|
||||
|
||||
this.$pollJob({
|
||||
jobId,
|
||||
title: this.$t(this.currentAction.label),
|
||||
description: resourceName,
|
||||
successMessage: `${this.$t('label.success')}`,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
loadingMessage: `${this.$t(this.currentAction.label)} ${this.$t('label.in.progress')}`,
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.fetchLoading = false
|
||||
this.closeAction()
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
})
|
||||
},
|
||||
onRemoveAction (record) {
|
||||
const params = {}
|
||||
params.zoneid = this.resource.zoneid
|
||||
for (const field in this.currentAction.args) {
|
||||
if (typeof this.currentAction.args[field] === 'function') {
|
||||
params[field] = this.currentAction.args[field](record)
|
||||
}
|
||||
}
|
||||
|
||||
this.fetchLoading = true
|
||||
api(this.currentAction.api, params).then(json => {
|
||||
const jsonResponseName = [this.currentAction.api, 'response'].join('').toLowerCase()
|
||||
const jobId = json[jsonResponseName].jobid
|
||||
const resourceName = record.name || record.uuid || record.id
|
||||
this.$pollJob({
|
||||
jobId,
|
||||
title: this.$t(this.currentAction.label),
|
||||
description: resourceName,
|
||||
successMessage: `${this.$t('label.success')}`,
|
||||
successMethod: () => {
|
||||
this.fetchData()
|
||||
},
|
||||
loadingMessage: `${this.$t(this.currentAction.label)} ${this.$t('label.in.progress')}`,
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
action: {
|
||||
isFetchData: false
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.fetchLoading = false
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.showAddModal = false
|
||||
},
|
||||
handleChangeUuid (field, data, uuid) {
|
||||
this.tagType = ''
|
||||
if (field !== 'tagtype') {
|
||||
return
|
||||
}
|
||||
const match = data.filter(item => item.uuid === uuid)
|
||||
if (match && match.length > 0) {
|
||||
this.tagType = match[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form-layout {
|
||||
width: 80vw;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
width: 450px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
86
ui/src/views/network/tungsten/TungstenNetworkAction.vue
Normal file
86
ui/src/views/network/tungsten/TungstenNetworkAction.vue
Normal file
@ -0,0 +1,86 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div class="tungsten-network-action">
|
||||
<action-button
|
||||
:actions="actions"
|
||||
:dataView="false"
|
||||
@exec-action="execAction" />
|
||||
<a-input-search
|
||||
class="search-input"
|
||||
:placeholder="$t('label.search')"
|
||||
@search="handleSearch" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ActionButton from '@/components/view/ActionButton'
|
||||
|
||||
export default {
|
||||
name: 'TungstenNetworkAction',
|
||||
components: {
|
||||
ActionButton
|
||||
},
|
||||
props: {
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 20
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
searchQuery: ''
|
||||
}
|
||||
},
|
||||
inject: ['onFetchData', 'onExecAction'],
|
||||
methods: {
|
||||
handleSearch (keyword) {
|
||||
this.searchQuery = keyword
|
||||
const query = {}
|
||||
query.page = this.page
|
||||
query.pageSize = this.pageSize
|
||||
query.searchQuery = this.searchQuery
|
||||
this.onFetchData(query)
|
||||
},
|
||||
execAction (action) {
|
||||
this.onExecAction(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.tungsten-network-action {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
|
||||
.search-input {
|
||||
width: 250px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
194
ui/src/views/network/tungsten/TungstenNetworkTable.vue
Normal file
194
ui/src/views/network/tungsten/TungstenNetworkTable.vue
Normal file
@ -0,0 +1,194 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
<template>
|
||||
<div class="tungsten-network-table">
|
||||
<a-table
|
||||
size="middle"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:pagination="false"
|
||||
:rowKey="(record, idx) => record.id || record.name || idx + '-' + Math.random()"
|
||||
:scroll="{ y: 350 }">
|
||||
<template #name="{ text, record }">
|
||||
<!-- <QuickView
|
||||
:actions="actions"
|
||||
:enabled="true"
|
||||
:resource="record"
|
||||
@exec-action="(action) => execAction(action, record)"/> -->
|
||||
<router-link v-if="apiName === 'listTungstenFabricPolicy'" :to="{ path: '/tungstenpolicy/' + record.uuid, query: { zoneid: resource.zoneid } }" >{{ text }}</router-link>
|
||||
<router-link v-else-if="apiName === 'listTungstenFabricApplicationPolicySet'" :to="{ path: '/tungstenpolicyset/' + record.uuid, query: { zoneid: resource.zoneid } }" >{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</template>
|
||||
<template #tungstenvms="{ record }">
|
||||
<ul v-if="record.tungstenvms.length > 0"><li v-for="item in record.tungstenvms" :key="item.uuid">{{ item.name }}</li></ul>
|
||||
</template>
|
||||
<template #network="{ record }">
|
||||
<ul v-if="record.network.length > 0"><li v-for="item in record.network" :key="item.uuid"><span v-if="item.name">{{ item.name }}</span></li></ul>
|
||||
</template>
|
||||
<template #firewallpolicy="{ record }">
|
||||
<span v-if="record.firewallpolicy.length > 0">{{ record.firewallpolicy.map(item => item.name).join(',') }}</span>
|
||||
</template>
|
||||
<template #firewallrule="{ record }">
|
||||
<span v-if="record.firewallrule.length > 0">{{ record.firewallrule[0].name }}</span>
|
||||
</template>
|
||||
<template #tungstenroutingpolicyterm="{ record }">
|
||||
<span v-if="record.tungstenroutingpolicyterm.length > 0">{{ record.tungstenroutingpolicyterm[0].name }}</span>
|
||||
</template>
|
||||
<template #vm="{ record }">
|
||||
<ul v-if="record.vm.length > 0"><li v-for="item in record.vm" :key="item.uuid">{{ item.name }}</li></ul>
|
||||
</template>
|
||||
<template #nic="{ record }">
|
||||
<ul v-if="record.nic.length > 0"><li v-for="item in record.nic" :key="item.uuid">{{ item.name }}</li></ul>
|
||||
</template>
|
||||
<template #tag="{ record }">
|
||||
<div class="tags" v-for="tag in record.tag" :key="tag.uuid">
|
||||
<a-tag :key="tag.uuid">{{ tag.name }}</a-tag>
|
||||
</div>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<span v-for="(action, index) in actions" :key="index" style="margin-right: 5px">
|
||||
<tooltip-button
|
||||
v-if="action.dataView && ('show' in action ? action.show(record, $store.getters) : true)"
|
||||
:tooltip="$t(action.label)"
|
||||
:danger="['delete-outlined', 'DeleteOutlined'].includes(action.icon)"
|
||||
:type="(['DeleteOutlined', 'delete-outlined'].includes(action.icon) ? 'primary' : 'default')"
|
||||
:icon="action.icon"
|
||||
@click="() => execAction(action, record)" />
|
||||
</span>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-pagination
|
||||
class="row-element"
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="itemCount"
|
||||
:showTotal="total => `${$t('label.showing')} ${Math.min(total, 1+((page-1)*pageSize))}-${Math.min(page*pageSize, total)} ${$t('label.of')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="pageSizeOptions"
|
||||
@change="changePage"
|
||||
@showSizeChange="changePageSize"
|
||||
showSizeChanger
|
||||
showQuickJumper>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mixinDevice } from '@/utils/mixin.js'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import QuickView from '@/components/view/QuickView'
|
||||
|
||||
export default {
|
||||
name: 'TungstenNetworkTable',
|
||||
components: { QuickView, TooltipButton },
|
||||
props: {
|
||||
apiName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
dataSource: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
resource: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
itemCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
searchQuery: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
mixins: [mixinDevice],
|
||||
inject: ['onFetchData', 'onExecAction'],
|
||||
computed: {
|
||||
pageSizeOptions () {
|
||||
const sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
|
||||
if (this.device !== 'desktop') {
|
||||
sizes.unshift(10)
|
||||
}
|
||||
return [...new Set(sizes)].sort(function (a, b) {
|
||||
return a - b
|
||||
}).map(String)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changePage (page, pageSize) {
|
||||
const query = {}
|
||||
query.page = page
|
||||
query.pageSize = pageSize
|
||||
query.searchQuery = this.searchQuery
|
||||
this.onFetchData(query)
|
||||
},
|
||||
changePageSize (currentPage, pageSize) {
|
||||
const query = {}
|
||||
query.page = currentPage
|
||||
query.pageSize = pageSize
|
||||
query.searchQuery = this.searchQuery
|
||||
this.onFetchData(query)
|
||||
},
|
||||
execAction (action, record) {
|
||||
this.onExecAction(action, record)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.tungsten-network-table {
|
||||
margin-top: 20px;
|
||||
|
||||
.row-element {
|
||||
margin-top: 20px;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 15px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -41,7 +41,7 @@
|
||||
<a-input
|
||||
v-model:value="form.name"
|
||||
:placeholder="$t('label.volumename')"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
</a-form-item>
|
||||
<a-form-item name="zoneId" ref="zoneId">
|
||||
<template #label>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user