This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.22 by this push:
new 9ec8cc4186f api,server,ui: improve listing public ip for associate
(#11591)
9ec8cc4186f is described below
commit 9ec8cc4186fb587a7a0e9684b52ca1f7057fe8f6
Author: Abhishek Kumar <[email protected]>
AuthorDate: Wed Nov 26 09:24:12 2025 +0100
api,server,ui: improve listing public ip for associate (#11591)
Signed-off-by: Abhishek Kumar <[email protected]>
---
.../user/address/ListPublicIpAddressesCmd.java | 2 +-
.../com/cloud/server/ManagementServerImpl.java | 50 ++++++++-----
.../com/cloud/server/ManagementServerImplTest.java | 66 ++++++++++++++---
ui/src/components/widgets/InfiniteScrollSelect.vue | 24 ++++++-
ui/src/views/network/IpAddressesTab.vue | 84 +++++++++-------------
utils/src/main/java/com/cloud/utils/EnumUtils.java | 2 +-
6 files changed, 146 insertions(+), 82 deletions(-)
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java
index 357f0c83ed7..57fd733d51d 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java
@@ -53,7 +53,7 @@ public class ListPublicIpAddressesCmd extends
BaseListRetrieveOnlyResourceCountC
@Parameter(name = ApiConstants.ALLOCATED_ONLY, type = CommandType.BOOLEAN,
description = "limits search results to allocated public IP addresses")
private Boolean allocatedOnly;
- @Parameter(name = ApiConstants.STATE, type = CommandType.STRING,
description = "lists all public IP addresses by state")
+ @Parameter(name = ApiConstants.STATE, type = CommandType.STRING,
description = "lists all public IP addresses by state. A comma-separated list
of states can be passed")
private String state;
@Parameter(name = ApiConstants.FOR_VIRTUAL_NETWORK, type =
CommandType.BOOLEAN, description = "the virtual network for the IP address")
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 9e8fdb60694..e6032662e92 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -823,6 +823,7 @@ import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.SSHKeyPairDao;
import com.cloud.user.dao.UserDao;
import com.cloud.user.dao.UserDataDao;
+import com.cloud.utils.EnumUtils;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.PasswordGenerator;
@@ -2419,6 +2420,22 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
return new Pair<>(result.first(), result.second());
}
+ protected List<IpAddress.State> getStatesForIpAddressSearch(final
ListPublicIpAddressesCmd cmd) {
+ final String statesStr = cmd.getState();
+ final List<IpAddress.State> states = new ArrayList<>();
+ if (StringUtils.isBlank(statesStr)) {
+ return states;
+ }
+ for (String s : StringUtils.split(statesStr, ",")) {
+ IpAddress.State state =
EnumUtils.getEnumIgnoreCase(IpAddress.State.class, s.trim());
+ if (state == null) {
+ throw new InvalidParameterValueException("Invalid state: " +
s);
+ }
+ states.add(state);
+ }
+ return states;
+ }
+
@Override
public Pair<List<? extends IpAddress>, Integer> searchForIPAddresses(final
ListPublicIpAddressesCmd cmd) {
final Long associatedNetworkId = cmd.getAssociatedNetworkId();
@@ -2429,20 +2446,20 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
final Long networkId = cmd.getNetworkId();
final Long vpcId = cmd.getVpcId();
- final String state = cmd.getState();
+ final List<IpAddress.State> states = getStatesForIpAddressSearch(cmd);
Boolean isAllocated = cmd.isAllocatedOnly();
if (isAllocated == null) {
- if (state != null &&
(state.equalsIgnoreCase(IpAddress.State.Free.name()) ||
state.equalsIgnoreCase(IpAddress.State.Reserved.name()))) {
+ if (states.contains(IpAddress.State.Free) ||
states.contains(IpAddress.State.Reserved)) {
isAllocated = Boolean.FALSE;
} else {
isAllocated = Boolean.TRUE; // default
}
} else {
- if (state != null &&
(state.equalsIgnoreCase(IpAddress.State.Free.name()) ||
state.equalsIgnoreCase(IpAddress.State.Reserved.name()))) {
+ if (states.contains(IpAddress.State.Free) ||
states.contains(IpAddress.State.Reserved)) {
if (isAllocated) {
throw new InvalidParameterValueException("Conflict:
allocatedonly is true but state is Free");
}
- } else if (state != null &&
state.equalsIgnoreCase(IpAddress.State.Allocated.name())) {
+ } else if (states.contains(IpAddress.State.Allocated)) {
isAllocated = Boolean.TRUE;
}
}
@@ -2521,10 +2538,8 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
Boolean isRecursive = cmd.isRecursive();
final List<Long> permittedAccounts = new ArrayList<>();
ListProjectResourcesCriteria listProjectResourcesCriteria = null;
- boolean isAllocatedOrReserved = false;
- if (isAllocated ||
IpAddress.State.Reserved.name().equalsIgnoreCase(state)) {
- isAllocatedOrReserved = true;
- }
+ boolean isAllocatedOrReserved = isAllocated ||
+ (states.size() == 1 &&
IpAddress.State.Reserved.equals(states.get(0)));
if (isAllocatedOrReserved || (vlanType == VlanType.VirtualNetwork &&
(caller.getType() != Account.Type.ADMIN || cmd.getDomainId() != null))) {
final Ternary<Long, Boolean, ListProjectResourcesCriteria>
domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(),
cmd.isRecursive(),
null);
@@ -2538,7 +2553,7 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
buildParameters(sb, cmd, vlanType == VlanType.VirtualNetwork ? true :
isAllocated);
SearchCriteria<IPAddressVO> sc = sb.create();
- setParameters(sc, cmd, vlanType, isAllocated);
+ setParameters(sc, cmd, vlanType, isAllocated, states);
if (isAllocatedOrReserved || (vlanType == VlanType.VirtualNetwork &&
(caller.getType() != Account.Type.ADMIN || cmd.getDomainId() != null))) {
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive,
permittedAccounts, listProjectResourcesCriteria);
@@ -2606,7 +2621,7 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
buildParameters(searchBuilder, cmd, false);
SearchCriteria<IPAddressVO> searchCriteria =
searchBuilder.create();
- setParameters(searchCriteria, cmd, vlanType, false);
+ setParameters(searchCriteria, cmd, vlanType, false, states);
searchCriteria.setParameters("state",
IpAddress.State.Free.name());
addrs.addAll(_publicIpAddressDao.search(searchCriteria,
searchFilter)); // Free IPs on shared network
}
@@ -2619,7 +2634,7 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
sb2.and("quarantinedPublicIpsIdsNIN", sb2.entity().getId(),
SearchCriteria.Op.NIN);
SearchCriteria<IPAddressVO> sc2 = sb2.create();
- setParameters(sc2, cmd, vlanType, isAllocated);
+ setParameters(sc2, cmd, vlanType, isAllocated, states);
sc2.setParameters("ids", freeAddrIds.toArray());
_publicIpAddressDao.buildQuarantineSearchCriteria(sc2);
addrs.addAll(_publicIpAddressDao.search(sc2, searchFilter)); //
Allocated + Free
@@ -2649,7 +2664,7 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
sb.and("isSourceNat", sb.entity().isSourceNat(), SearchCriteria.Op.EQ);
sb.and("isStaticNat", sb.entity().isOneToOneNat(),
SearchCriteria.Op.EQ);
sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ);
- sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
+ sb.and("state", sb.entity().getState(), SearchCriteria.Op.IN);
sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ);
sb.and(FOR_SYSTEMVMS, sb.entity().isForSystemVms(),
SearchCriteria.Op.EQ);
@@ -2692,7 +2707,8 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
}
}
- protected void setParameters(SearchCriteria<IPAddressVO> sc, final
ListPublicIpAddressesCmd cmd, VlanType vlanType, Boolean isAllocated) {
+ protected void setParameters(SearchCriteria<IPAddressVO> sc, final
ListPublicIpAddressesCmd cmd, VlanType vlanType,
+ Boolean isAllocated, List<IpAddress.State> states) {
final Object keyword = cmd.getKeyword();
final Long physicalNetworkId = cmd.getPhysicalNetworkId();
final Long sourceNetworkId = cmd.getNetworkId();
@@ -2703,7 +2719,6 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
final Boolean sourceNat = cmd.isSourceNat();
final Boolean staticNat = cmd.isStaticNat();
final Boolean forDisplay = cmd.getDisplay();
- final String state = cmd.getState();
final Boolean forSystemVms = cmd.getForSystemVMs();
final boolean forProvider = cmd.isForProvider();
final Map<String, String> tags = cmd.getTags();
@@ -2760,13 +2775,14 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
sc.setParameters("display", forDisplay);
}
- if (state != null) {
- sc.setParameters("state", state);
+ if (CollectionUtils.isNotEmpty(states)) {
+ sc.setParameters("state", states.toArray());
} else if (isAllocated != null && isAllocated) {
sc.setParameters("state", IpAddress.State.Allocated);
}
- if
(IpAddressManagerImpl.getSystemvmpublicipreservationmodestrictness().value() &&
IpAddress.State.Free.name().equalsIgnoreCase(state)) {
+ if
(IpAddressManagerImpl.getSystemvmpublicipreservationmodestrictness().value() &&
+ states.contains(IpAddress.State.Free)) {
sc.setParameters(FOR_SYSTEMVMS, false);
} else {
sc.setParameters(FOR_SYSTEMVMS, forSystemVms);
diff --git
a/server/src/test/java/com/cloud/server/ManagementServerImplTest.java
b/server/src/test/java/com/cloud/server/ManagementServerImplTest.java
index ebced92f8fe..2f52df982b7 100644
--- a/server/src/test/java/com/cloud/server/ManagementServerImplTest.java
+++ b/server/src/test/java/com/cloud/server/ManagementServerImplTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
@@ -258,14 +259,14 @@ public class ManagementServerImplTest {
Mockito.when(cmd.getId()).thenReturn(null);
Mockito.when(cmd.isSourceNat()).thenReturn(null);
Mockito.when(cmd.isStaticNat()).thenReturn(null);
- Mockito.when(cmd.getState()).thenReturn(IpAddress.State.Free.name());
Mockito.when(cmd.getTags()).thenReturn(null);
- spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.FALSE);
+ List<IpAddress.State> states =
Collections.singletonList(IpAddress.State.Free);
+ spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.FALSE,
states);
Mockito.verify(sc, Mockito.times(1)).setJoinParameters("vlanSearch",
"vlanType", VlanType.VirtualNetwork);
Mockito.verify(sc, Mockito.times(1)).setParameters("display", false);
Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId",
10L);
- Mockito.verify(sc, Mockito.times(1)).setParameters("state", "Free");
+ Mockito.verify(sc, Mockito.times(1)).setParameters("state",
states.toArray());
Mockito.verify(sc, Mockito.times(1)).setParameters("forsystemvms",
false);
}
@@ -281,14 +282,14 @@ public class ManagementServerImplTest {
Mockito.when(cmd.getId()).thenReturn(null);
Mockito.when(cmd.isSourceNat()).thenReturn(null);
Mockito.when(cmd.isStaticNat()).thenReturn(null);
- Mockito.when(cmd.getState()).thenReturn(IpAddress.State.Free.name());
Mockito.when(cmd.getTags()).thenReturn(null);
- spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.FALSE);
+ List<IpAddress.State> states =
Collections.singletonList(IpAddress.State.Free);
+ spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.FALSE,
states);
Mockito.verify(sc, Mockito.times(1)).setJoinParameters("vlanSearch",
"vlanType", VlanType.VirtualNetwork);
Mockito.verify(sc, Mockito.times(1)).setParameters("display", false);
Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId",
10L);
- Mockito.verify(sc, Mockito.times(1)).setParameters("state", "Free");
+ Mockito.verify(sc, Mockito.times(1)).setParameters("state",
states.toArray());
Mockito.verify(sc, Mockito.times(1)).setParameters("forsystemvms",
false);
}
@@ -304,13 +305,13 @@ public class ManagementServerImplTest {
Mockito.when(cmd.getId()).thenReturn(null);
Mockito.when(cmd.isSourceNat()).thenReturn(null);
Mockito.when(cmd.isStaticNat()).thenReturn(null);
- Mockito.when(cmd.getState()).thenReturn(null);
Mockito.when(cmd.getTags()).thenReturn(null);
- spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.TRUE);
+ spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.TRUE,
Collections.emptyList());
Mockito.verify(sc, Mockito.times(1)).setJoinParameters("vlanSearch",
"vlanType", VlanType.VirtualNetwork);
Mockito.verify(sc, Mockito.times(1)).setParameters("display", false);
Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId",
10L);
+ Mockito.verify(sc, Mockito.times(1)).setParameters("state",
IpAddress.State.Allocated);
Mockito.verify(sc, Mockito.times(1)).setParameters("forsystemvms",
false);
}
@@ -326,13 +327,13 @@ public class ManagementServerImplTest {
Mockito.when(cmd.getId()).thenReturn(null);
Mockito.when(cmd.isSourceNat()).thenReturn(null);
Mockito.when(cmd.isStaticNat()).thenReturn(null);
- Mockito.when(cmd.getState()).thenReturn(null);
Mockito.when(cmd.getTags()).thenReturn(null);
- spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.TRUE);
+ spy.setParameters(sc, cmd, VlanType.VirtualNetwork, Boolean.TRUE,
Collections.emptyList());
Mockito.verify(sc, Mockito.times(1)).setJoinParameters("vlanSearch",
"vlanType", VlanType.VirtualNetwork);
Mockito.verify(sc, Mockito.times(1)).setParameters("display", false);
Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId",
10L);
+ Mockito.verify(sc, Mockito.times(1)).setParameters("state",
IpAddress.State.Allocated);
Mockito.verify(sc, Mockito.times(1)).setParameters("forsystemvms",
false);
}
@@ -1033,4 +1034,49 @@ public class ManagementServerImplTest {
Assert.assertNotNull(spy.getExternalVmConsole(virtualMachine, host));
Mockito.verify(extensionManager).getInstanceConsole(virtualMachine,
host);
}
+
+ @Test
+ public void getStatesForIpAddressSearchReturnsValidStates() {
+ ListPublicIpAddressesCmd cmd =
Mockito.mock(ListPublicIpAddressesCmd.class);
+ Mockito.when(cmd.getState()).thenReturn("Allocated ,free");
+ List<IpAddress.State> result = spy.getStatesForIpAddressSearch(cmd);
+ Assert.assertEquals(2, result.size());
+ Assert.assertTrue(result.contains(IpAddress.State.Allocated));
+ Assert.assertTrue(result.contains(IpAddress.State.Free));
+ }
+
+ @Test
+ public void getStatesForIpAddressSearchReturnsEmptyListForNullState() {
+ ListPublicIpAddressesCmd cmd =
Mockito.mock(ListPublicIpAddressesCmd.class);
+ Mockito.when(cmd.getState()).thenReturn(null);
+ List<IpAddress.State> result = spy.getStatesForIpAddressSearch(cmd);
+ Assert.assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void getStatesForIpAddressSearchReturnsEmptyListForBlankState() {
+ ListPublicIpAddressesCmd cmd =
Mockito.mock(ListPublicIpAddressesCmd.class);
+ Mockito.when(cmd.getState()).thenReturn(" ");
+ List<IpAddress.State> result = spy.getStatesForIpAddressSearch(cmd);
+ Assert.assertTrue(result.isEmpty());
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void getStatesForIpAddressSearchThrowsExceptionForInvalidState() {
+ ListPublicIpAddressesCmd cmd =
Mockito.mock(ListPublicIpAddressesCmd.class);
+ Mockito.when(cmd.getState()).thenReturn("InvalidState");
+ spy.getStatesForIpAddressSearch(cmd);
+ }
+
+ @Test
+ public void getStatesForIpAddressSearchHandlesMixedValidAndInvalidStates()
{
+ ListPublicIpAddressesCmd cmd =
Mockito.mock(ListPublicIpAddressesCmd.class);
+ Mockito.when(cmd.getState()).thenReturn("Allocated,InvalidState");
+ try {
+ spy.getStatesForIpAddressSearch(cmd);
+ Assert.fail("Expected InvalidParameterValueException to be
thrown");
+ } catch (InvalidParameterValueException e) {
+ Assert.assertEquals("Invalid state: InvalidState", e.getMessage());
+ }
+ }
}
diff --git a/ui/src/components/widgets/InfiniteScrollSelect.vue
b/ui/src/components/widgets/InfiniteScrollSelect.vue
index 608eeebf133..122feafb2a0 100644
--- a/ui/src/components/widgets/InfiniteScrollSelect.vue
+++ b/ui/src/components/widgets/InfiniteScrollSelect.vue
@@ -43,6 +43,7 @@
- defaultOption (Object, optional): Preselected object to include initially
- showIcon (Boolean, optional): Whether to show icon for the options.
Default is true
- defaultIcon (String, optional): Icon to be shown when there is no resource
icon for the option. Default is 'cloud-outlined'
+ - autoSelectFirstOption (Boolean, optional): Whether to automatically select
the first option when options are loaded. Default is false
Events:
- @change-option-value (Function): Emits the selected option value(s) when
value(s) changes. Do not use @change as it will give warnings and may not work
@@ -81,7 +82,7 @@
<resource-icon v-if="option.icon && option.icon.base64image"
:image="option.icon.base64image" size="1x" style="margin-right: 5px"/>
<render-icon v-else :icon="defaultIcon" style="margin-right: 5px" />
</span>
- <span>{{ option[optionLabelKey] }}</span>
+ <span>{{ optionLabelFn ? optionLabelFn(option) :
option[optionLabelKey] }}</span>
</span>
</a-select-option>
</a-select>
@@ -120,6 +121,10 @@ export default {
type: String,
default: 'name'
},
+ optionLabelFn: {
+ type: Function,
+ default: null
+ },
defaultOption: {
type: Object,
default: null
@@ -135,6 +140,10 @@ export default {
pageSize: {
type: Number,
default: null
+ },
+ autoSelectFirstOption: {
+ type: Boolean,
+ default: false
}
},
data () {
@@ -147,11 +156,12 @@ export default {
searchTimer: null,
scrollHandlerAttached: false,
preselectedOptionValue: null,
- successiveFetches: 0
+ successiveFetches: 0,
+ canSelectFirstOption: false
}
},
created () {
- this.addDefaultOptionIfNeeded(true)
+ this.addDefaultOptionIfNeeded()
},
mounted () {
this.preselectedOptionValue = this.$attrs.value
@@ -208,6 +218,7 @@ export default {
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
+ this.canSelectFirstOption = true
if (this.successiveFetches === 0) {
this.loading = false
}
@@ -218,6 +229,12 @@ export default {
(Array.isArray(this.preselectedOptionValue) &&
this.preselectedOptionValue.length === 0) ||
this.successiveFetches >= this.maxSuccessiveFetches) {
this.resetPreselectedOptionValue()
+ if (!this.canSelectFirstOption && this.autoSelectFirstOption &&
this.options.length > 0) {
+ this.$nextTick(() => {
+ this.preselectedOptionValue = this.options[0][this.optionValueKey]
+ this.onChange(this.preselectedOptionValue)
+ })
+ }
return
}
const matchValue = Array.isArray(this.preselectedOptionValue) ?
this.preselectedOptionValue[0] : this.preselectedOptionValue
@@ -239,6 +256,7 @@ export default {
},
addDefaultOptionIfNeeded () {
if (this.defaultOption) {
+ this.canSelectFirstOption = true
this.options.push(this.defaultOption)
}
},
diff --git a/ui/src/views/network/IpAddressesTab.vue
b/ui/src/views/network/IpAddressesTab.vue
index ee9d1eff42b..37ebc29f19d 100644
--- a/ui/src/views/network/IpAddressesTab.vue
+++ b/ui/src/views/network/IpAddressesTab.vue
@@ -148,20 +148,17 @@
<a-alert :message="$t('message.action.acquire.ip')" type="warning" />
<a-form layout="vertical" style="margin-top: 10px">
<a-form-item :label="$t('label.ipaddress')">
- <a-select
+ <infinite-scroll-select
v-focus="true"
- style="width: 100%;"
v-model:value="acquireIp"
- showSearch
- optionFilterProp="label"
- :filterOption="(input, option) => {
- return option.label.toLowerCase().indexOf(input.toLowerCase())
>= 0
- }" >
- <a-select-option
- v-for="ip in listPublicIpAddress"
- :key="ip.ipaddress"
- :label="ip.ipaddress + '(' + ip.state + ')'">{{ ip.ipaddress
}} ({{ ip.state }})</a-select-option>
- </a-select>
+ api="listPublicIpAddresses"
+ :apiParams="listApiParamsForAssociate"
+ resourceType="publicipaddress"
+ optionValueKey="ipaddress"
+ :optionLabelFn="ip => ip.ipaddress + ' (' + ip.state + ')'"
+ defaultIcon="environment-outlined"
+ :autoSelectFirstOption="true"
+ @change-option-value="(ip) => acquireIp = ip" />
</a-form-item>
<div :span="24" class="action-button">
<a-button @click="onCloseModal">{{ $t('label.cancel') }}</a-button>
@@ -212,13 +209,15 @@ import Status from '@/components/widgets/Status'
import TooltipButton from '@/components/widgets/TooltipButton'
import BulkActionView from '@/components/view/BulkActionView'
import eventBus from '@/config/eventBus'
+import InfiniteScrollSelect from '@/components/widgets/InfiniteScrollSelect'
export default {
name: 'IpAddressesTab',
components: {
Status,
TooltipButton,
- BulkActionView
+ BulkActionView,
+ InfiniteScrollSelect
},
props: {
resource: {
@@ -281,7 +280,6 @@ export default {
showAcquireIp: false,
acquireLoading: false,
acquireIp: null,
- listPublicIpAddress: [],
changeSourceNat: false,
zoneExtNetProvider: ''
}
@@ -302,6 +300,26 @@ export default {
}
},
inject: ['parentFetchData'],
+ computed: {
+ listApiParams () {
+ const params = {
+ zoneid: this.resource.zoneid,
+ domainid: this.resource.domainid,
+ account: this.resource.account,
+ forvirtualnetwork: true,
+ allocatedonly: false
+ }
+ if (['nsx', 'netris'].includes(this.zoneExtNetProvider?.toLowerCase())) {
+ params.forprovider = true
+ }
+ return params
+ },
+ listApiParamsForAssociate () {
+ const params = this.listApiParams
+ params.state = 'Free,Reserved'
+ return params
+ }
+ },
methods: {
fetchData () {
const params = {
@@ -344,19 +362,9 @@ export default {
}).catch(reject)
})
},
- fetchListPublicIpAddress () {
+ fetchListPublicIpAddress (state) {
return new Promise((resolve, reject) => {
- const params = {
- zoneid: this.resource.zoneid,
- domainid: this.resource.domainid,
- account: this.resource.account,
- forvirtualnetwork: true,
- allocatedonly: false
- }
- if (['nsx',
'netris'].includes(this.zoneExtNetProvider?.toLowerCase())) {
- params.forprovider = true
- }
- getAPI('listPublicIpAddresses', params).then(json => {
+ getAPI('listPublicIpAddresses', this.listApiParams).then(json => {
const listPublicIps =
json.listpublicipaddressesresponse.publicipaddress || []
resolve(listPublicIps)
}).catch(reject)
@@ -554,30 +562,6 @@ export default {
},
async onShowAcquireIp () {
this.showAcquireIp = true
- this.acquireLoading = true
- this.listPublicIpAddress = []
-
- try {
- const listPublicIpAddress = await this.fetchListPublicIpAddress()
- listPublicIpAddress.forEach(item => {
- if (item.state === 'Free' || item.state === 'Reserved') {
- this.listPublicIpAddress.push({
- ipaddress: item.ipaddress,
- state: item.state
- })
- }
- })
- this.listPublicIpAddress.sort(function (a, b) {
- if (a.ipaddress < b.ipaddress) { return -1 }
- if (a.ipaddress > b.ipaddress) { return 1 }
- return 0
- })
- this.acquireIp = this.listPublicIpAddress &&
this.listPublicIpAddress.length > 0 ? this.listPublicIpAddress[0].ipaddress :
null
- this.acquireLoading = false
- } catch (e) {
- this.acquireLoading = false
- this.$notifyError(e)
- }
},
onCloseModal () {
this.showAcquireIp = false
diff --git a/utils/src/main/java/com/cloud/utils/EnumUtils.java
b/utils/src/main/java/com/cloud/utils/EnumUtils.java
index 02b6a25b895..380b595a0ad 100644
--- a/utils/src/main/java/com/cloud/utils/EnumUtils.java
+++ b/utils/src/main/java/com/cloud/utils/EnumUtils.java
@@ -19,7 +19,7 @@
package com.cloud.utils;
-public class EnumUtils {
+public class EnumUtils extends org.apache.commons.lang3.EnumUtils {
public static String listValues(Enum<?>[] enums) {
StringBuilder b = new StringBuilder("[");