refactor: refactor create volume

1. Refactor create volume
2. Disable click submit button when quota is insufficient

Change-Id: I16c28f5b6041d575c2b27cf7fa815ab248971187
This commit is contained in:
Jingwei.Zhang 2022-06-29 15:41:13 +08:00
parent ef8024f50b
commit 15503b110a

View File

@ -20,17 +20,25 @@ import {
volumeStatus, volumeStatus,
multiTip, multiTip,
snapshotTypeTip, snapshotTypeTip,
getQuotaInfo,
getAdd,
fetchQuota,
getQuota,
onVolumeSizeChange,
setCreateVolumeCount,
setCreateVolumeSize,
setCreateVolumeType,
} from 'resources/cinder/volume'; } from 'resources/cinder/volume';
import globalSnapshotStore from 'stores/cinder/snapshot'; import globalSnapshotStore from 'stores/cinder/snapshot';
import globalImageStore from 'stores/glance/image'; import globalImageStore from 'stores/glance/image';
import globalVolumeStore from 'stores/cinder/volume'; import globalVolumeStore from 'stores/cinder/volume';
import globalVolumeTypeStore from 'stores/cinder/volume-type'; import globalVolumeTypeStore from 'stores/cinder/volume-type';
import globalProjectStore from 'stores/keystone/project';
import globalBackupStore from 'stores/cinder/backup'; import globalBackupStore from 'stores/cinder/backup';
import { InputNumber, Badge, message as $message } from 'antd'; import { InputNumber, message as $message } from 'antd';
import { toJS } from 'mobx'; import { toJS } from 'mobx';
import { FormAction } from 'containers/Action'; import { FormAction } from 'containers/Action';
import classnames from 'classnames'; import classnames from 'classnames';
import { isEmpty, isObject } from 'lodash';
import { import {
getImageSystemTabs, getImageSystemTabs,
getImageOS, getImageOS,
@ -44,6 +52,14 @@ import styles from './index.less';
export class Create extends FormAction { export class Create extends FormAction {
init() { init() {
this.state = {
...this.state,
quotaLoading: true,
count: 1,
sharedDisabled: false,
confirmCount: 0,
};
this.message = '';
this.snapshotStore = globalSnapshotStore; this.snapshotStore = globalSnapshotStore;
this.imageStore = globalImageStore; this.imageStore = globalImageStore;
this.volumeStore = globalVolumeStore; this.volumeStore = globalVolumeStore;
@ -53,12 +69,6 @@ export class Create extends FormAction {
this.getAvailZones(); this.getAvailZones();
this.getImages(); this.getImages();
this.getVolumeTypes(); this.getVolumeTypes();
this.state = {
...this.state,
count: 1,
sharedDisabled: false,
confirmCount: 0,
};
} }
static id = 'volume-create'; static id = 'volume-create';
@ -81,6 +91,23 @@ export class Create extends FormAction {
return Promise.resolve(true); return Promise.resolve(true);
} }
get disableSubmit() {
const { quotaLoading } = this.state;
if (quotaLoading) {
return true;
}
const { cinderQuota = {} } = globalProjectStore;
const { add, error } = getAdd(cinderQuota);
const disable = add === 0;
if (!disable) {
this.message = '';
} else if (error !== this.message) {
$message.error(error);
this.message = error;
}
return disable;
}
get instanceName() { get instanceName() {
const { name } = this.values || {}; const { name } = this.values || {};
const { count = 1 } = this.state; const { count = 1 } = this.state;
@ -94,7 +121,7 @@ export class Create extends FormAction {
} }
get errorText() { get errorText() {
if (this.msg) { if (this.message) {
return t( return t(
'Unable to create volume: insufficient quota to create resources.' 'Unable to create volume: insufficient quota to create resources.'
); );
@ -107,79 +134,23 @@ export class Create extends FormAction {
} }
getVolumeQuota() { getVolumeQuota() {
const quotaAll = toJS(this.volumeStore.quotaSet) || {}; const { quota = {} } = this.state;
if (isEmpty(quotaAll)) { return getQuota(quota);
return [];
}
Object.values(quotaAll).forEach((it) => {
if (isObject(it)) {
it.used = it.in_use;
}
});
const { volume_type } = this.state;
const { name } = volume_type || {};
const result = {
volumes: quotaAll.volumes,
gigabytes: quotaAll.gigabytes,
};
if (name) {
result[`volumes_${name}`] = quotaAll[`volumes_${name}`];
result[`gigabytes_${name}`] = quotaAll[`gigabytes_${name}`];
}
return result;
} }
get quotaInfo() { get quotaInfo() {
const quota = this.getVolumeQuota(); return getQuotaInfo(this);
const { volumes = {}, gigabytes = {} } = quota; }
const { limit } = volumes || {};
if (!limit) {
return [];
}
const { volume_type, size = 0, count = 1 } = this.state; get defaultSize() {
const { name } = volume_type || {}; return this.quotaIsLimit && this.maxSize < 10 ? this.maxSize : 10;
const volume = {
...volumes,
add: count,
name: 'volume',
title: t('Volume'),
};
const sizeInfo = {
...gigabytes,
add: count * size,
name: 'gigabytes',
title: t('volume gigabytes'),
type: 'line',
};
if (!name) {
return [volume, sizeInfo];
}
const typeQuota = quota[`volumes_${name}`] || {};
const typeSizeQuota = quota[`gigabytes_${name}`] || {};
const detailInfo = {
...typeQuota,
add: count,
name: `volumes_${name}`,
title: t('{name} type', { name }),
type: 'line',
};
const detailSizeInfo = {
...typeSizeQuota,
add: count * size,
name: `gigabytes_${name}`,
title: t('{name} type gigabytes', { name }),
type: 'line',
};
return [volume, sizeInfo, detailInfo, detailSizeInfo];
} }
get defaultValue() { get defaultValue() {
const size = this.quotaIsLimit && this.maxSize < 10 ? this.maxSize : 10;
const { initVolumeType } = this.state; const { initVolumeType } = this.state;
const values = { const values = {
source: this.sourceTypes[0], source: this.sourceTypes[0],
size, size: this.defaultSize,
project: this.currentProjectName, project: this.currentProjectName,
availableZone: (this.availableZones[0] || []).value, availableZone: (this.availableZones[0] || []).value,
volume_type: initVolumeType, volume_type: initVolumeType,
@ -237,20 +208,14 @@ export class Create extends FormAction {
]; ];
} }
get quota() {
const { volumes = {} } = this.getVolumeQuota();
return volumes;
}
get quotaIsLimit() { get quotaIsLimit() {
const { gigabytes: { limit } = {} } = this.getVolumeQuota(); const { gigabytes: { limit } = {} } = this.getVolumeQuota();
return limit !== -1; return limit !== -1;
} }
get maxSize() { get maxSize() {
const { gigabytes: { limit = 10, in_use = 0, reserved = 0 } = {} } = const { gigabytes: { left = 0 } = {} } = this.getVolumeQuota();
this.getVolumeQuota(); return left === -1 ? 1000 : left;
return limit !== -1 ? limit - in_use - reserved : 1000;
} }
getAvailZones() { getAvailZones() {
@ -264,14 +229,17 @@ export class Create extends FormAction {
async getVolumeTypes() { async getVolumeTypes() {
const types = await this.volumeTypeStore.fetchList(); const types = await this.volumeTypeStore.fetchList();
if (types.length > 0) { if (types.length > 0) {
const defaultType = types[0];
const { id, name } = defaultType;
const initVolumeType = { const initVolumeType = {
selectedRowKeys: [types[0].id], selectedRowKeys: [id],
selectedRows: [types[0]], selectedRows: [defaultType],
}; };
setCreateVolumeType(name);
this.setState( this.setState(
{ {
initVolumeType, initVolumeType,
volume_type: types[0], volume_type: defaultType,
}, },
() => { () => {
this.updateFormValue('volume_type', initVolumeType); this.updateFormValue('volume_type', initVolumeType);
@ -282,7 +250,8 @@ export class Create extends FormAction {
} }
async getQuota() { async getQuota() {
await this.volumeStore.fetchQuota(); await fetchQuota(this, 0);
setCreateVolumeSize(this.defaultSize);
this.onCountChange(1); this.onCountChange(1);
this.updateDefaultValue(); this.updateDefaultValue();
} }
@ -321,12 +290,18 @@ export class Create extends FormAction {
onVolumeTypeChange = (value) => { onVolumeTypeChange = (value) => {
const { selectedRows = [] } = value; const { selectedRows = [] } = value;
if (selectedRows.length === 0) { if (selectedRows.length === 0) {
setCreateVolumeType('');
this.setState({ this.setState({
multiattach: false, multiattach: false,
}); });
return; return;
} }
const { id, extra_specs: { multiattach = 'False' } = {} } = selectedRows[0]; const {
id,
extra_specs: { multiattach = 'False' } = {},
name,
} = selectedRows[0];
setCreateVolumeType(name);
if (this.sourceTypeIsSnapshot) { if (this.sourceTypeIsSnapshot) {
const { const {
initVolumeType: { selectedRowKeys = [] }, initVolumeType: { selectedRowKeys = [] },
@ -520,6 +495,7 @@ export class Create extends FormAction {
description: `${minSize}GiB-${this.maxSize}GiB`, description: `${minSize}GiB-${this.maxSize}GiB`,
required: this.quotaIsLimit, required: this.quotaIsLimit,
hidden: !this.quotaIsLimit, hidden: !this.quotaIsLimit,
onChange: onVolumeSizeChange,
}, },
{ {
name: 'size', name: 'size',
@ -528,6 +504,7 @@ export class Create extends FormAction {
min: minSize, min: minSize,
hidden: this.quotaIsLimit, hidden: this.quotaIsLimit,
required: !this.quotaIsLimit, required: !this.quotaIsLimit,
onChange: onVolumeSizeChange,
}, },
{ {
type: 'divider', type: 'divider',
@ -549,6 +526,7 @@ export class Create extends FormAction {
onCountChangeCallback() {} onCountChangeCallback() {}
onCountChange = (value) => { onCountChange = (value) => {
setCreateVolumeCount(value);
this.setState( this.setState(
{ {
count: value, count: value,
@ -561,69 +539,12 @@ export class Create extends FormAction {
); );
}; };
checkQuotaDetail = (quota) => {
if (!quota || isEmpty(quota)) {
return true;
}
const { limit, add, reserved = 0 } = quota || {};
if (limit === -1) {
return true;
}
return limit >= add + reserved;
};
getQuotaErrorMsg = (quota) => {
const { limit, used, reserved, add, title } = quota;
const left = limit - used - reserved;
return t(
'Quota: Insufficient { name } quota to create resources, please adjust resource quantity or quota(left { left }, input { input }).',
{
name: title,
left,
input: add,
}
);
};
checkQuotaAll = () => {
const results = this.quotaInfo;
if (!results.length) {
return '';
}
const [quota = {}, sizeQuota = {}, typeQuota = {}, typeSizeQuota = {}] =
results;
let msg = '';
const quotas = [quota, sizeQuota, typeQuota, typeSizeQuota];
const errorQuota = quotas.find((it) => !this.checkQuotaDetail(it));
if (errorQuota) {
msg = this.getQuotaErrorMsg(errorQuota);
}
return msg;
};
renderBadge() {
const msg = this.checkQuotaAll();
if (!msg) {
this.msg = '';
return null;
}
if (msg && this.msg !== msg) {
$message.error(msg);
this.msg = msg;
}
return <Badge status="error" text={msg} />;
}
renderExtra() {
return this.renderBadge();
}
getCountMax = () => { getCountMax = () => {
const { limit, used, reserved } = this.quota; const { volumes: { left = 0 } = {} } = this.getVolumeQuota();
if (!limit || limit === -1) { if (left === -1) {
return 100; return Infinity;
} }
return limit - used - reserved; return left;
}; };
renderFooterLeft() { renderFooterLeft() {
@ -644,15 +565,14 @@ export class Create extends FormAction {
value={count} value={count}
className={classnames(styles.input, 'volume-count')} className={classnames(styles.input, 'volume-count')}
/> />
{this.renderExtra()}
</div> </div>
); );
} }
onSubmit = (data) => { onSubmit = (data) => {
const { count } = this.state; const { count } = this.state;
if (this.msg) { if (this.message) {
return Promise.reject(this.msg); return Promise.reject(this.message);
} }
const { const {
backup, backup,