feat: support quota info when snapshot create volume
1. Support quota info when snapshot create volume 2. Disable click submit button when quota is insufficient Change-Id: I81a3bde0f4bd7bdc403bea8176754c5dc5a32373
This commit is contained in:
parent
78cb485068
commit
b605ac01c4
@ -15,6 +15,14 @@
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import { ModalAction } from 'containers/Action';
|
||||
import globalVolumeStore from 'stores/cinder/volume';
|
||||
import {
|
||||
getQuotaInfo,
|
||||
checkQuotaDisable,
|
||||
fetchQuota,
|
||||
setCreateVolumeType,
|
||||
onVolumeSizeChange,
|
||||
onVolumeTypeChange,
|
||||
} from 'resources/cinder/volume';
|
||||
|
||||
export class CreateVolume extends ModalAction {
|
||||
static id = 'create';
|
||||
@ -22,8 +30,9 @@ export class CreateVolume extends ModalAction {
|
||||
static title = t('Create Volume');
|
||||
|
||||
init() {
|
||||
this.volumeStore = globalVolumeStore;
|
||||
this.store = globalVolumeStore;
|
||||
this.getVolumeTypes();
|
||||
fetchQuota(this, this.item.size);
|
||||
}
|
||||
|
||||
get name() {
|
||||
@ -34,6 +43,22 @@ export class CreateVolume extends ModalAction {
|
||||
|
||||
static allowed = () => Promise.resolve(true);
|
||||
|
||||
static get disableSubmit() {
|
||||
return checkQuotaDisable();
|
||||
}
|
||||
|
||||
static get showQuota() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get showQuota() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get quotaInfo() {
|
||||
return getQuotaInfo(this);
|
||||
}
|
||||
|
||||
get volumeTypeParams() {
|
||||
return {};
|
||||
}
|
||||
@ -42,19 +67,21 @@ export class CreateVolume extends ModalAction {
|
||||
const { volume_id: id } = this.item;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [_, volume] = await Promise.all([
|
||||
this.volumeStore.fetchVolumeTypes(this.volumeTypeParams),
|
||||
this.volumeStore.fetchDetail({ id }),
|
||||
this.store.fetchVolumeTypes(this.volumeTypeParams),
|
||||
this.store.fetchDetail({ id }),
|
||||
]);
|
||||
const { volume_type: volumeType } = volume;
|
||||
const typeItem = this.volumeTypes.find((it) => it.label === volumeType);
|
||||
if (typeItem) {
|
||||
this.volumeType = typeItem.value;
|
||||
setCreateVolumeType(volumeType);
|
||||
}
|
||||
this.updateFormValue('volume_type', this.volumeType);
|
||||
this.updateDefaultValue();
|
||||
}
|
||||
|
||||
get volumeTypes() {
|
||||
return this.volumeStore.volumeTypes || [];
|
||||
return this.store.volumeTypes || [];
|
||||
}
|
||||
|
||||
get defaultValue() {
|
||||
@ -94,6 +121,7 @@ export class CreateVolume extends ModalAction {
|
||||
min: this.minSize,
|
||||
extra: `${t('Min size')}: ${this.minSize}GiB`,
|
||||
required: true,
|
||||
onChange: onVolumeSizeChange,
|
||||
},
|
||||
{
|
||||
name: 'more',
|
||||
@ -107,6 +135,8 @@ export class CreateVolume extends ModalAction {
|
||||
options: this.volumeTypes,
|
||||
placeholder: t('Please select volume type'),
|
||||
hidden: !more,
|
||||
onChange: onVolumeTypeChange,
|
||||
allowClear: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -15,6 +15,9 @@
|
||||
import React from 'react';
|
||||
import { yesNoOptions } from 'utils/constants';
|
||||
import { toLocalTimeFilter } from 'utils/index';
|
||||
import globalProjectStore from 'stores/keystone/project';
|
||||
import globalVolumeStore from 'stores/cinder/volume';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
export const volumeStatus = {
|
||||
available: t('Available'),
|
||||
@ -338,3 +341,185 @@ export const getVolumeColumnsList = (self) => {
|
||||
}
|
||||
return columns;
|
||||
};
|
||||
|
||||
// deal with quota
|
||||
export function setCreateVolumeSize(value) {
|
||||
globalVolumeStore.setCreateVolumeSize(value);
|
||||
}
|
||||
|
||||
export function setCreateVolumeType(value) {
|
||||
globalVolumeStore.setCreateVolumeType(value);
|
||||
}
|
||||
|
||||
export function setCreateVolumeCount(value) {
|
||||
globalVolumeStore.setCreateVolumeCount(value);
|
||||
}
|
||||
|
||||
export async function fetchQuota(self, size) {
|
||||
setCreateVolumeCount(1);
|
||||
setCreateVolumeSize(size);
|
||||
setCreateVolumeType('');
|
||||
self.setState({
|
||||
quota: {},
|
||||
quotaLoading: true,
|
||||
});
|
||||
const result = await globalProjectStore.fetchProjectCinderQuota();
|
||||
self.setState({
|
||||
quota: result,
|
||||
quotaLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
export const getQuota = (cinderQuota) => {
|
||||
if (isEmpty(cinderQuota)) {
|
||||
return {};
|
||||
}
|
||||
const { volumeTypeForCreate } = globalVolumeStore;
|
||||
const { volumes = {}, gigabytes = {} } = cinderQuota || {};
|
||||
const typeQuotaKey = `volumes_${volumeTypeForCreate}`;
|
||||
const sizeQuotaKey = `gigabytes_${volumeTypeForCreate}`;
|
||||
const typeQuota = (cinderQuota || {})[typeQuotaKey] || {};
|
||||
const typeSizeQuota = (cinderQuota || {})[sizeQuotaKey] || {};
|
||||
return {
|
||||
volumes,
|
||||
gigabytes,
|
||||
typeQuota,
|
||||
typeSizeQuota,
|
||||
};
|
||||
};
|
||||
|
||||
const getErrorMessage = ({ name, left, input }) => {
|
||||
const error = t(
|
||||
'Quota: Insufficient { name } quota to create resources, please adjust resource quantity or quota(left { left }, input { input }).',
|
||||
{
|
||||
name,
|
||||
left,
|
||||
input,
|
||||
}
|
||||
);
|
||||
return error;
|
||||
};
|
||||
|
||||
export const getAdd = (cinderQuota) => {
|
||||
if (isEmpty(cinderQuota)) {
|
||||
return {};
|
||||
}
|
||||
const { volumes, gigabytes, typeQuota, typeSizeQuota } =
|
||||
getQuota(cinderQuota);
|
||||
const { left = 0 } = volumes || {};
|
||||
const { left: sizeLeft = 0, limit: sizeLimit } = gigabytes || {};
|
||||
const { left: typeLeft = 0 } = typeQuota || {};
|
||||
const { left: typeSizeLeft = 0, limit: typeSizeLimit } = typeSizeQuota || {};
|
||||
const {
|
||||
volumeSizeForCreate: size = 0,
|
||||
volumeCountForCreate: count = 1,
|
||||
volumeTypeForCreate: type = '',
|
||||
} = globalVolumeStore;
|
||||
const zero = {
|
||||
add: 0,
|
||||
addSize: 0,
|
||||
};
|
||||
const totalSize = size * count;
|
||||
const create = {
|
||||
add: count,
|
||||
addSize: totalSize,
|
||||
};
|
||||
if (left >= 0 && left < count) {
|
||||
const error = getErrorMessage({
|
||||
name: t('volume'),
|
||||
left,
|
||||
input: count,
|
||||
});
|
||||
return { ...zero, error };
|
||||
}
|
||||
if (sizeLimit !== -1 && sizeLeft < totalSize) {
|
||||
const error = getErrorMessage({
|
||||
name: t('gigabytes'),
|
||||
left: sizeLeft,
|
||||
input: totalSize,
|
||||
});
|
||||
return { ...zero, error };
|
||||
}
|
||||
if (isEmpty(typeQuota)) {
|
||||
return create;
|
||||
}
|
||||
if (typeLeft >= 0 && typeLeft < count) {
|
||||
const error = getErrorMessage({
|
||||
name: t('{name} type', { name: type }),
|
||||
left: typeLeft,
|
||||
input: count,
|
||||
});
|
||||
return { ...zero, error };
|
||||
}
|
||||
if (typeSizeLimit !== -1 && typeSizeLeft < totalSize) {
|
||||
const error = getErrorMessage({
|
||||
name: t('{name} type gigabytes', { name: type }),
|
||||
left: typeSizeLeft,
|
||||
input: totalSize,
|
||||
});
|
||||
return { ...zero, error };
|
||||
}
|
||||
return create;
|
||||
};
|
||||
|
||||
export const getQuotaInfo = (self) => {
|
||||
const { volumeTypeForCreate: name } = globalVolumeStore;
|
||||
const { quota = {}, quotaLoading } = self.state;
|
||||
if (quotaLoading || isEmpty(quota)) {
|
||||
return [];
|
||||
}
|
||||
const {
|
||||
volumes = {},
|
||||
gigabytes = {},
|
||||
typeQuota = {},
|
||||
typeSizeQuota = {},
|
||||
} = getQuota(quota);
|
||||
const { add, addSize } = getAdd(quota);
|
||||
const volumeData = {
|
||||
...volumes,
|
||||
add,
|
||||
name: 'volume',
|
||||
title: t('Volume'),
|
||||
};
|
||||
const sizeData = {
|
||||
...gigabytes,
|
||||
add: addSize,
|
||||
name: 'gigabytes',
|
||||
title: t('Gigabytes (GiB)'),
|
||||
type: 'line',
|
||||
};
|
||||
if (!name) {
|
||||
return [volumeData, sizeData];
|
||||
}
|
||||
const typeData = {
|
||||
...typeQuota,
|
||||
add,
|
||||
name: 'type',
|
||||
title: t('{name} type', { name }),
|
||||
type: 'line',
|
||||
};
|
||||
const typeSizeData = {
|
||||
...typeSizeQuota,
|
||||
add: addSize,
|
||||
name: 'typeSize',
|
||||
title: t('{name} type gigabytes', { name }),
|
||||
type: 'line',
|
||||
};
|
||||
return [volumeData, sizeData, typeData, typeSizeData];
|
||||
};
|
||||
|
||||
export const checkQuotaDisable = () => {
|
||||
const { cinderQuota = {} } = globalProjectStore;
|
||||
const { add } = getAdd(cinderQuota);
|
||||
return add === 0;
|
||||
};
|
||||
|
||||
export const onVolumeSizeChange = (value) => {
|
||||
setCreateVolumeSize(value);
|
||||
};
|
||||
|
||||
export const onVolumeTypeChange = (value) => {
|
||||
const { volumeTypes = [] } = globalVolumeStore;
|
||||
const item = volumeTypes.find((it) => it.value === value);
|
||||
setCreateVolumeType(item.label);
|
||||
};
|
||||
|
@ -13,7 +13,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { action, observable } from 'mobx';
|
||||
import { isOsDisk } from 'resources/cinder/volume';
|
||||
import { renderFilterMap } from 'utils/index';
|
||||
import client from 'client';
|
||||
import Base from 'stores/base';
|
||||
@ -32,6 +31,15 @@ export class VolumeStore extends Base {
|
||||
@observable
|
||||
quotaSet = {};
|
||||
|
||||
@observable
|
||||
volumeTypeForCreate = '';
|
||||
|
||||
@observable
|
||||
volumeSizeForCreate = 0;
|
||||
|
||||
@observable
|
||||
volumeCountForCreate = 1;
|
||||
|
||||
get client() {
|
||||
return client.cinder.volumes;
|
||||
}
|
||||
@ -56,10 +64,15 @@ export class VolumeStore extends Base {
|
||||
return this.skylineClient.extension.volumes(params);
|
||||
}
|
||||
|
||||
isOsDisk(item) {
|
||||
const { isOsDisk } = require('resources/cinder/volume');
|
||||
return isOsDisk(item);
|
||||
}
|
||||
|
||||
get mapper() {
|
||||
return (volume) => ({
|
||||
...volume,
|
||||
disk_tag: isOsDisk(volume) ? 'os_disk' : 'data_disk',
|
||||
disk_tag: this.isOsDisk(volume) ? 'os_disk' : 'data_disk',
|
||||
description: volume.description || (volume.origin_data || {}).description,
|
||||
delete_interval:
|
||||
volume.metadata && volume.metadata.delete_interval
|
||||
@ -214,6 +227,28 @@ export class VolumeStore extends Base {
|
||||
}));
|
||||
this.originalVolumeTypes = data || [];
|
||||
}
|
||||
|
||||
@action
|
||||
setCreateVolumeSize(size = 0) {
|
||||
this.volumeSizeForCreate = size;
|
||||
}
|
||||
|
||||
@action
|
||||
setCreateVolumeType(type = '') {
|
||||
this.volumeTypeForCreate = type;
|
||||
}
|
||||
|
||||
@action
|
||||
setCreateVolumeCount(count = 1) {
|
||||
this.volumeCountForCreate = count;
|
||||
}
|
||||
|
||||
@action
|
||||
setCreateVolumeInfo({ size = 0, type = '', count = 1 } = {}) {
|
||||
this.setCreateVolumeSize(size);
|
||||
this.setCreateVolumeType(type);
|
||||
this.setCreateVolumeCount(count);
|
||||
}
|
||||
}
|
||||
|
||||
const globalVolumeStore = new VolumeStore();
|
||||
|
Loading…
Reference in New Issue
Block a user