Merge "feat: Show quota info when create server group"
This commit is contained in:
commit
b8caadf202
@ -74,8 +74,8 @@ export default class BaseForm extends React.Component {
|
|||||||
this.unMountActions && this.unMountActions();
|
this.unMountActions && this.unMountActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
get canSubmit() {
|
get disableSubmit() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
@ -534,7 +534,7 @@ export default class BaseForm extends React.Component {
|
|||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={!this.canSubmit}
|
disabled={this.disableSubmit}
|
||||||
type="primary"
|
type="primary"
|
||||||
className={styles.submit}
|
className={styles.submit}
|
||||||
onClick={this.onClickSubmit}
|
onClick={this.onClickSubmit}
|
||||||
@ -651,6 +651,9 @@ export default class BaseForm extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderRightTopExtra() {
|
renderRightTopExtra() {
|
||||||
|
if (this.isModal) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const content = this.renderQuota();
|
const content = this.renderQuota();
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return null;
|
return null;
|
||||||
@ -663,6 +666,17 @@ export default class BaseForm extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderModalRightExtra() {
|
||||||
|
if (!this.isModal) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const content = this.renderQuota();
|
||||||
|
if (!content) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return <div className={styles['modal-right-extra-wrapper']}>{content}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const wrapperPadding =
|
const wrapperPadding =
|
||||||
this.listUrl || this.isStep || (this.isModal && this.tips)
|
this.listUrl || this.isStep || (this.isModal && this.tips)
|
||||||
@ -679,10 +693,8 @@ export default class BaseForm extends React.Component {
|
|||||||
formStyle.height = `calc(100% - ${tipHeight}px)`;
|
formStyle.height = `calc(100% - ${tipHeight}px)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
|
||||||
<div
|
const formDiv = (
|
||||||
className={classnames(styles.wrapper, wrapperPadding, this.className)}
|
|
||||||
>
|
|
||||||
<Spin spinning={this.isSubmitting} tip={this.renderSubmittingTip()}>
|
<Spin spinning={this.isSubmitting} tip={this.renderSubmittingTip()}>
|
||||||
{tips}
|
{tips}
|
||||||
{this.renderRightTopExtra()}
|
{this.renderRightTopExtra()}
|
||||||
@ -691,6 +703,21 @@ export default class BaseForm extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
{this.renderFooter()}
|
{this.renderFooter()}
|
||||||
</Spin>
|
</Spin>
|
||||||
|
);
|
||||||
|
const onlyForm = !this.isModal || (this.isModal && !this.showQuota);
|
||||||
|
const modalInner =
|
||||||
|
this.isModal && !onlyForm ? (
|
||||||
|
<Row justify="space-between" align="top">
|
||||||
|
<Col span={18}>{formDiv}</Col>
|
||||||
|
<Col span={6}>{this.renderModalRightExtra()}</Col>
|
||||||
|
</Row>
|
||||||
|
) : null;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classnames(styles.wrapper, wrapperPadding, this.className)}
|
||||||
|
>
|
||||||
|
{onlyForm && formDiv}
|
||||||
|
{modalInner}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -139,3 +139,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-right-extra-wrapper {
|
||||||
|
border-left: solid 2px @gray-2;
|
||||||
|
}
|
||||||
|
@ -429,16 +429,18 @@ export class ActionButton extends Component {
|
|||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
|
|
||||||
getModalWidth = (size) => {
|
getModalWidth = (action) => {
|
||||||
|
const { modalSize: size, showQuota = false } = action;
|
||||||
|
const multi = showQuota ? 1.25 : 1;
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 'small':
|
case 'small':
|
||||||
return 520;
|
return 520 * multi;
|
||||||
case 'middle':
|
case 'middle':
|
||||||
return 720;
|
return 720 * multi;
|
||||||
case 'large':
|
case 'large':
|
||||||
return 1200;
|
return 1200 * multi;
|
||||||
default:
|
default:
|
||||||
return 520;
|
return 520 * multi;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -455,8 +457,15 @@ export class ActionButton extends Component {
|
|||||||
}
|
}
|
||||||
const { title, action, item, containerProps, items } = this.props;
|
const { title, action, item, containerProps, items } = this.props;
|
||||||
const ActionComponent = action;
|
const ActionComponent = action;
|
||||||
const { modalSize, okText, cancelText, id, className, readOnly } = action;
|
const {
|
||||||
const width = this.getModalWidth(modalSize);
|
okText,
|
||||||
|
cancelText,
|
||||||
|
id,
|
||||||
|
className,
|
||||||
|
readOnly,
|
||||||
|
disableSubmit = false,
|
||||||
|
} = action;
|
||||||
|
const width = this.getModalWidth(action);
|
||||||
const modalProps = {
|
const modalProps = {
|
||||||
title,
|
title,
|
||||||
visible,
|
visible,
|
||||||
@ -464,6 +473,9 @@ export class ActionButton extends Component {
|
|||||||
width,
|
width,
|
||||||
onOk: () => this.onClickModalActionOk(),
|
onOk: () => this.onClickModalActionOk(),
|
||||||
onCancel: this.onClickModalActionCancel,
|
onCancel: this.onClickModalActionCancel,
|
||||||
|
okButtonProps: {
|
||||||
|
disabled: disableSubmit,
|
||||||
|
},
|
||||||
confirmLoading: submitLoading,
|
confirmLoading: submitLoading,
|
||||||
okText,
|
okText,
|
||||||
cancelText,
|
cancelText,
|
||||||
|
@ -42,6 +42,14 @@ export default class ModalAction extends BaseForm {
|
|||||||
return 'small';
|
return 'small';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get showQuota() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showQuota() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
get labelCol() {
|
get labelCol() {
|
||||||
const size = this.getModalSize();
|
const size = this.getModalSize();
|
||||||
if (size === 'large') {
|
if (size === 'large') {
|
||||||
|
@ -17,6 +17,7 @@ import { inject, observer } from 'mobx-react';
|
|||||||
import globalServerGroupStore from 'stores/nova/server-group';
|
import globalServerGroupStore from 'stores/nova/server-group';
|
||||||
import { ModalAction } from 'containers/Action';
|
import { ModalAction } from 'containers/Action';
|
||||||
import policyType from 'resources/nova/server-group';
|
import policyType from 'resources/nova/server-group';
|
||||||
|
import globalProjectStore from 'src/stores/keystone/project';
|
||||||
|
|
||||||
export class Create extends ModalAction {
|
export class Create extends ModalAction {
|
||||||
static id = 'create';
|
static id = 'create';
|
||||||
@ -24,7 +25,11 @@ export class Create extends ModalAction {
|
|||||||
static title = t('Create Server Group');
|
static title = t('Create Server Group');
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
this.state.quota = {};
|
||||||
|
this.state.quotaLoading = true;
|
||||||
this.store = globalServerGroupStore;
|
this.store = globalServerGroupStore;
|
||||||
|
this.projectStore = globalProjectStore;
|
||||||
|
this.getQuota();
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
@ -35,6 +40,45 @@ export class Create extends ModalAction {
|
|||||||
|
|
||||||
static allowed = () => Promise.resolve(true);
|
static allowed = () => Promise.resolve(true);
|
||||||
|
|
||||||
|
static get disableSubmit() {
|
||||||
|
const { novaQuota: { server_groups: { left = 0 } = {} } = {} } =
|
||||||
|
globalProjectStore;
|
||||||
|
return left === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get showQuota() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showQuota() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getQuota() {
|
||||||
|
const result = await this.projectStore.fetchProjectNovaQuota();
|
||||||
|
const { server_groups: quota = {} } = result || {};
|
||||||
|
this.setState({
|
||||||
|
quota,
|
||||||
|
quotaLoading: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get quotaInfo() {
|
||||||
|
const { quota = {}, quotaLoading } = this.state;
|
||||||
|
if (quotaLoading) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const { left = 0 } = quota;
|
||||||
|
const add = left === 0 ? 0 : 1;
|
||||||
|
const data = {
|
||||||
|
...quota,
|
||||||
|
add,
|
||||||
|
name: 'server_groups',
|
||||||
|
title: t('Server Group'),
|
||||||
|
};
|
||||||
|
return [data];
|
||||||
|
}
|
||||||
|
|
||||||
get formItems() {
|
get formItems() {
|
||||||
const policies = Object.keys(policyType).map((it) => ({
|
const policies = Object.keys(policyType).map((it) => ({
|
||||||
value: it,
|
value: it,
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import { action, observable } from 'mobx';
|
import { action, observable } from 'mobx';
|
||||||
import { getGiBValue } from 'utils/index';
|
import { getGiBValue } from 'utils/index';
|
||||||
import { isNil, isEmpty } from 'lodash';
|
import { isNil, isEmpty, isObject } from 'lodash';
|
||||||
import client from 'client';
|
import client from 'client';
|
||||||
import Base from 'stores/base';
|
import Base from 'stores/base';
|
||||||
import globalRootStore from 'stores/root';
|
import globalRootStore from 'stores/root';
|
||||||
@ -23,6 +23,9 @@ export class ProjectStore extends Base {
|
|||||||
@observable
|
@observable
|
||||||
quota = {};
|
quota = {};
|
||||||
|
|
||||||
|
@observable
|
||||||
|
novaQuota = {};
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
groupRoleList = [];
|
groupRoleList = [];
|
||||||
|
|
||||||
@ -261,14 +264,9 @@ export class ProjectStore extends Base {
|
|||||||
...neutronQuota,
|
...neutronQuota,
|
||||||
...renameShareQuota,
|
...renameShareQuota,
|
||||||
};
|
};
|
||||||
const quotaKey = Object.keys(quota);
|
const newQuota = this.updateQuotaData(quota);
|
||||||
quotaKey.forEach((it) => {
|
this.quota = newQuota;
|
||||||
if (quota[it].in_use !== undefined) {
|
return newQuota;
|
||||||
quota[it].used = quota[it].in_use;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.quota = quota;
|
|
||||||
return quota;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
omitNil = (obj) => {
|
omitNil = (obj) => {
|
||||||
@ -437,6 +435,36 @@ export class ProjectStore extends Base {
|
|||||||
const result = await this.client.groups.roles.delete(id, groupId, roleId);
|
const result = await this.client.groups.roles.delete(id, groupId, roleId);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLeftQuotaData = (data) => {
|
||||||
|
const { used = 0, limit = 0, reserved = 0 } = data;
|
||||||
|
if (limit === -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return limit - used - reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
updateQuotaData = (quota) => {
|
||||||
|
const newData = JSON.parse(JSON.stringify(quota));
|
||||||
|
Object.keys(newData).forEach((it) => {
|
||||||
|
if (isObject(newData[it])) {
|
||||||
|
if (newData[it].in_use !== undefined) {
|
||||||
|
newData[it].used = newData[it].in_use;
|
||||||
|
}
|
||||||
|
newData[it].left = this.getLeftQuotaData(newData[it]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newData;
|
||||||
|
};
|
||||||
|
|
||||||
|
@action
|
||||||
|
async fetchProjectNovaQuota() {
|
||||||
|
const result = await this.novaQuotaClient.detail(this.currentProjectId);
|
||||||
|
const { quota_set: quota } = result;
|
||||||
|
const novaQuota = this.updateQuotaData(quota);
|
||||||
|
this.novaQuota = novaQuota;
|
||||||
|
return novaQuota;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalProjectStore = new ProjectStore();
|
const globalProjectStore = new ProjectStore();
|
||||||
|
Loading…
Reference in New Issue
Block a user