mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Fix link to removed volumes being shown in info card and list view (#8833)
* Framework for validating links in the front-end * Rename valid links map in the list view
This commit is contained in:
parent
54c8b71fb5
commit
49cd5ba64a
@ -576,6 +576,7 @@ public class ApiConstants {
|
|||||||
public static final String AGGREGATE_NAME = "aggregatename";
|
public static final String AGGREGATE_NAME = "aggregatename";
|
||||||
public static final String POOL_NAME = "poolname";
|
public static final String POOL_NAME = "poolname";
|
||||||
public static final String VOLUME_NAME = "volumename";
|
public static final String VOLUME_NAME = "volumename";
|
||||||
|
public static final String VOLUME_STATE = "volumestate";
|
||||||
public static final String SNAPSHOT_POLICY = "snapshotpolicy";
|
public static final String SNAPSHOT_POLICY = "snapshotpolicy";
|
||||||
public static final String SNAPSHOT_RESERVATION = "snapshotreservation";
|
public static final String SNAPSHOT_RESERVATION = "snapshotreservation";
|
||||||
public static final String IP_NETWORK_LIST = "iptonetworklist";
|
public static final String IP_NETWORK_LIST = "iptonetworklist";
|
||||||
|
|||||||
@ -71,6 +71,10 @@ public class SnapshotResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "type of the disk volume")
|
@Param(description = "type of the disk volume")
|
||||||
private String volumeType;
|
private String volumeType;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VOLUME_STATE)
|
||||||
|
@Param(description = "state of the disk volume")
|
||||||
|
private String volumeState;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.CREATED)
|
@SerializedName(ApiConstants.CREATED)
|
||||||
@Param(description = " the date the snapshot was created")
|
@Param(description = " the date the snapshot was created")
|
||||||
private Date created;
|
private Date created;
|
||||||
@ -199,6 +203,10 @@ public class SnapshotResponse extends BaseResponseWithTagInformation implements
|
|||||||
this.volumeType = volumeType;
|
this.volumeType = volumeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVolumeState(String volumeState) {
|
||||||
|
this.volumeState = volumeState;
|
||||||
|
}
|
||||||
|
|
||||||
public void setCreated(Date created) {
|
public void setCreated(Date created) {
|
||||||
this.created = created;
|
this.created = created;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ SELECT
|
|||||||
`volumes`.`uuid` AS `volume_uuid`,
|
`volumes`.`uuid` AS `volume_uuid`,
|
||||||
`volumes`.`name` AS `volume_name`,
|
`volumes`.`name` AS `volume_name`,
|
||||||
`volumes`.`volume_type` AS `volume_type`,
|
`volumes`.`volume_type` AS `volume_type`,
|
||||||
|
`volumes`.`state` AS `volume_state`,
|
||||||
`volumes`.`size` AS `volume_size`,
|
`volumes`.`size` AS `volume_size`,
|
||||||
`data_center`.`id` AS `data_center_id`,
|
`data_center`.`id` AS `data_center_id`,
|
||||||
`data_center`.`uuid` AS `data_center_uuid`,
|
`data_center`.`uuid` AS `data_center_uuid`,
|
||||||
|
|||||||
@ -659,6 +659,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
snapshotResponse.setVolumeId(volume.getUuid());
|
snapshotResponse.setVolumeId(volume.getUuid());
|
||||||
snapshotResponse.setVolumeName(volume.getName());
|
snapshotResponse.setVolumeName(volume.getName());
|
||||||
snapshotResponse.setVolumeType(volume.getVolumeType().name());
|
snapshotResponse.setVolumeType(volume.getVolumeType().name());
|
||||||
|
snapshotResponse.setVolumeState(volume.getState().name());
|
||||||
snapshotResponse.setVirtualSize(volume.getSize());
|
snapshotResponse.setVirtualSize(volume.getSize());
|
||||||
DataCenter zone = ApiDBUtils.findZoneById(volume.getDataCenterId());
|
DataCenter zone = ApiDBUtils.findZoneById(volume.getDataCenterId());
|
||||||
if (zone != null) {
|
if (zone != null) {
|
||||||
|
|||||||
@ -128,6 +128,7 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
|
|||||||
snapshotResponse.setVolumeId(snapshot.getVolumeUuid());
|
snapshotResponse.setVolumeId(snapshot.getVolumeUuid());
|
||||||
snapshotResponse.setVolumeName(snapshot.getVolumeName());
|
snapshotResponse.setVolumeName(snapshot.getVolumeName());
|
||||||
snapshotResponse.setVolumeType(snapshot.getVolumeType().name());
|
snapshotResponse.setVolumeType(snapshot.getVolumeType().name());
|
||||||
|
snapshotResponse.setVolumeState(snapshot.getVolumeState().name());
|
||||||
snapshotResponse.setVirtualSize(snapshot.getVolumeSize());
|
snapshotResponse.setVirtualSize(snapshot.getVolumeSize());
|
||||||
VolumeVO volume = ApiDBUtils.findVolumeById(snapshot.getVolumeId());
|
VolumeVO volume = ApiDBUtils.findVolumeById(snapshot.getVolumeId());
|
||||||
if (volume != null && volume.getVolumeType() == Type.ROOT && volume.getInstanceId() != null) {
|
if (volume != null && volume.getVolumeType() == Type.ROOT && volume.getInstanceId() != null) {
|
||||||
|
|||||||
@ -130,6 +130,10 @@ public class SnapshotJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
Volume.Type volumeType = Volume.Type.UNKNOWN;
|
Volume.Type volumeType = Volume.Type.UNKNOWN;
|
||||||
|
|
||||||
|
@Column(name = "volume_state")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
Volume.State volumeState;
|
||||||
|
|
||||||
@Column(name = "volume_size")
|
@Column(name = "volume_size")
|
||||||
Long volumeSize;
|
Long volumeSize;
|
||||||
|
|
||||||
@ -297,6 +301,10 @@ public class SnapshotJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||||||
return volumeType;
|
return volumeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Volume.State getVolumeState() {
|
||||||
|
return volumeState;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getVolumeSize() {
|
public Long getVolumeSize() {
|
||||||
return volumeSize;
|
return volumeSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -442,7 +442,8 @@
|
|||||||
<div class="resource-detail-item__label">{{ $t('label.volume') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.volume') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<hdd-outlined />
|
<hdd-outlined />
|
||||||
<router-link :to="{ path: '/volume/' + resource.volumeid }">{{ resource.volumename || resource.volume || resource.volumeid }} </router-link>
|
<router-link v-if="validLinks.volume" :to="{ path: '/volume/' + resource.volumeid }">{{ resource.volumename || resource.volume || resource.volumeid }} </router-link>
|
||||||
|
<span v-else>{{ resource.volumename || resource.volume || resource.volumeid }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="resource-detail-item" v-if="resource.associatednetworkid">
|
<div class="resource-detail-item" v-if="resource.associatednetworkid">
|
||||||
@ -783,6 +784,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { api } from '@/api'
|
import { api } from '@/api'
|
||||||
import { createPathBasedOnVmType } from '@/utils/plugins'
|
import { createPathBasedOnVmType } from '@/utils/plugins'
|
||||||
|
import { validateLinks } from '@/utils/links'
|
||||||
import Console from '@/components/widgets/Console'
|
import Console from '@/components/widgets/Console'
|
||||||
import OsLogo from '@/components/widgets/OsLogo'
|
import OsLogo from '@/components/widgets/OsLogo'
|
||||||
import Status from '@/components/widgets/Status'
|
import Status from '@/components/widgets/Status'
|
||||||
@ -848,7 +850,8 @@ export default {
|
|||||||
vpc: '',
|
vpc: '',
|
||||||
network: ''
|
network: ''
|
||||||
},
|
},
|
||||||
newResource: {}
|
newResource: {},
|
||||||
|
validLinks: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -865,6 +868,7 @@ export default {
|
|||||||
this.newResource = newData
|
this.newResource = newData
|
||||||
this.showKeys = false
|
this.showKeys = false
|
||||||
this.setData()
|
this.setData()
|
||||||
|
this.validLinks = validateLinks(this.$router, this.isStatic, this.resource)
|
||||||
|
|
||||||
if ('apikey' in this.resource) {
|
if ('apikey' in this.resource) {
|
||||||
this.getUserKeys()
|
this.getUserKeys()
|
||||||
|
|||||||
@ -167,7 +167,8 @@
|
|||||||
<router-link :to="{ path: getVmRouteUsingType(record) + record.virtualmachineid }">{{ text }}</router-link>
|
<router-link :to="{ path: getVmRouteUsingType(record) + record.virtualmachineid }">{{ text }}</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'volumename'">
|
<template v-if="column.key === 'volumename'">
|
||||||
<router-link :to="{ path: '/volume/' + record.volumeid }">{{ text }}</router-link>
|
<router-link v-if="resourceIdToValidLinksMap[record.id]?.volume" :to="{ path: '/volume/' + record.volumeid }">{{ text }}</router-link>
|
||||||
|
<span v-else>{{ text }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'size'">
|
<template v-if="column.key === 'size'">
|
||||||
<span v-if="text && $route.path === '/kubernetes'">
|
<span v-if="text && $route.path === '/kubernetes'">
|
||||||
@ -488,6 +489,7 @@ import TooltipButton from '@/components/widgets/TooltipButton'
|
|||||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
import ResourceLabel from '@/components/widgets/ResourceLabel'
|
import ResourceLabel from '@/components/widgets/ResourceLabel'
|
||||||
import { createPathBasedOnVmType } from '@/utils/plugins'
|
import { createPathBasedOnVmType } from '@/utils/plugins'
|
||||||
|
import { validateLinks } from '@/utils/links'
|
||||||
import cronstrue from 'cronstrue/i18n'
|
import cronstrue from 'cronstrue/i18n'
|
||||||
import moment from 'moment-timezone'
|
import moment from 'moment-timezone'
|
||||||
|
|
||||||
@ -576,6 +578,18 @@ export default {
|
|||||||
notification: 'storageallocatedthreshold',
|
notification: 'storageallocatedthreshold',
|
||||||
disable: 'storageallocateddisablethreshold'
|
disable: 'storageallocateddisablethreshold'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
resourceIdToValidLinksMap: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
items: {
|
||||||
|
deep: true,
|
||||||
|
handler (newData, oldData) {
|
||||||
|
if (newData === oldData) return
|
||||||
|
this.items.forEach(record => {
|
||||||
|
this.resourceIdToValidLinksMap[record.id] = validateLinks(this.$router, false, record)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
36
ui/src/utils/links.js
Normal file
36
ui/src/utils/links.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
export function validateLinks (router, isStatic, resource) {
|
||||||
|
const validLinks = {
|
||||||
|
volume: false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStatic) {
|
||||||
|
return validLinks
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource.volumeid && router.resolve('/volume/' + resource.volumeid).matched[0].redirect !== '/exception/404') {
|
||||||
|
if (resource.volumestate) {
|
||||||
|
validLinks.volume = resource.volumestate !== 'Expunged'
|
||||||
|
} else {
|
||||||
|
validLinks.volume = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validLinks
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user