refactor: Refactor manage project quota

Refactor manage project quota

Change-Id: Id81e42080fe9ad296be68a4dedeb24bb24daf9c5
This commit is contained in:
Jingwei.Zhang 2021-09-22 18:04:40 +08:00
parent ae266d3d74
commit 3109d9bc98
3 changed files with 224 additions and 369 deletions

View File

@ -34,8 +34,8 @@ export const quotaCardList = [
{ text: t('Instances'), key: 'instances' },
{ text: t('vCPUs'), key: 'cores' },
{ text: t('Memory'), key: 'ram' },
{ text: t('Server Group'), key: 'server_groups' },
{ text: t('Key Pair'), key: 'key_pairs' },
{ text: t('Server Group'), key: 'server_groups' },
],
},
{
@ -66,19 +66,46 @@ export const quotaCardList = [
},
{
text: t('Network'),
type: 'network',
type: 'networks',
value: [
{ text: t('Router'), key: 'router' },
{ text: t('Network'), key: 'network' },
{ text: t('Subnet'), key: 'subnet' },
{ text: t('Floating IP'), key: 'floatingip' },
{ text: `${t('port')}`, key: 'port' },
{ text: t('Port'), key: 'port' },
{ text: t('Security Group'), key: 'security_group' },
{ text: t('Security Group Rule'), key: 'security_group_rule' },
],
},
];
export const getVolumeTypeCards = (data) => {
const value = data.map((item, index) => {
return {
index,
value: [
{
text: t('{name} type', { name: item.name }),
key: `volumes_${item.name}`,
},
{
text: t('{name} type gigabytes(GB)', { name: item.name }),
key: `gigabytes_${item.name}`,
},
{
text: t('{name} type snapshots', { name: item.name }),
key: `snapshots_${item.name}`,
},
],
};
});
return {
text: t('Storage Types'),
type: 'volumeTypes',
value,
};
};
export class QuotaOverview extends Component {
constructor(props) {
super(props);
@ -117,30 +144,7 @@ export class QuotaOverview extends Component {
}
get volumeTypesQuota() {
const volumeTypes = this.volumeTypeData.map((item, index) => {
return {
index,
value: [
{
text: t('{name} type', { name: item.name }),
key: `volumes_${item.name}`,
},
{
text: t('{name} type gigabytes(GB)', { name: item.name }),
key: `gigabytes_${item.name}`,
},
{
text: t('{name} type snapshots', { name: item.name }),
key: `snapshots_${item.name}`,
},
],
};
});
return {
text: t('Storage Types'),
type: 'VolumeTypes',
value: volumeTypes,
};
return getVolumeTypeCards(this.volumeTypeData);
}
get quotaCardList() {

View File

@ -13,10 +13,14 @@
// limitations under the License.
import { inject, observer } from 'mobx-react';
import globalProjectStore from 'stores/keystone/project';
import globalProjectStore, { ProjectStore } from 'stores/keystone/project';
import React from 'react';
import { ModalAction } from 'containers/Action';
import { VolumeTypeStore } from 'stores/cinder/volume-type';
import {
quotaCardList,
getVolumeTypeCards,
} from 'pages/base/containers/Overview/components/QuotaOverview';
export class QuotaManager extends ModalAction {
static id = 'quota-management';
@ -25,33 +29,29 @@ export class QuotaManager extends ModalAction {
init() {
this.store = globalProjectStore;
this.projectStore = new ProjectStore();
this.volumeTypeStore = new VolumeTypeStore();
// this.getQuota();
this.getData();
}
get name() {
return t('Edit quota');
}
componentDidMount() {
this.getData();
async getData() {
const { id: project_id } = this.item;
await Promise.all([
this.projectStore.fetchProjectQuota({
project_id,
}),
this.volumeTypeStore.fetchProjectVolumeTypes(project_id),
]);
this.updateDefaultValue();
}
getData = async () => {
const { id: project_id } = this.item;
await this.store.fetchProjectQuota({
project_id,
});
await this.volumeTypeStore.fetchProjectVolumeTypes(project_id);
};
get tips() {
return (
<>
{t(
'quota set to -1 means there is no quota limit on the current resource'
)}
</>
return t(
'quota set to -1 means there is no quota limit on the current resource'
);
}
@ -62,99 +62,21 @@ export class QuotaManager extends ModalAction {
static allowed = () => Promise.resolve(true);
get volumeTypesData() {
const volumeTypes = [];
const { projectVolumeTypes: data = [] } = this.volumeTypeStore;
if (data[0] && this.formRef.current) {
data.forEach((item) => {
volumeTypes.push.apply(volumeTypes, [
{
text: t('{name} type', { name: item.name }),
key: `volumes_${item.name}`,
},
{
text: t('{name} type gigabytes(GB)', { name: item.name }),
key: `gigabytes_${item.name}`,
},
{
text: t('{name} type snapshots', { name: item.name }),
key: `snapshots_${item.name}`,
},
]);
});
}
return volumeTypes;
}
get defaultValue() {
const {
quota: {
instances,
cores,
security_group,
ram,
ipsecpolicy,
key_pairs,
security_group_rule,
router,
volumes,
network,
subnet,
floatingip,
vpnservice,
vpntunnel,
gigabytes,
backups,
port,
backup_gigabytes,
endpoint_group,
loadbalancer,
snapshots,
server_groups,
server_group_members,
},
} = this.store;
if (instances && this.formRef.current) {
const initData = {
more: false,
instances: (instances || {}).limit,
cores: (cores || {}).limit,
security_group: (security_group || {}).limit,
ram: (ram || {}).limit,
ipsecpolicy: (ipsecpolicy || {}).limit,
key_pairs: (key_pairs || {}).limit,
security_group_rule: (security_group_rule || {}).limit,
router: (router || {}).limit,
volumes: (volumes || {}).limit,
network: (network || {}).limit,
subnet: (subnet || {}).limit,
floatingip: (floatingip || {}).limit,
vpnservice: (vpnservice || {}).limit,
vpntunnel: (vpntunnel || {}).limit,
port: (port || {}).limit,
gigabytes: (gigabytes || {}).limit,
backup_gigabytes: (backup_gigabytes || {}).limit,
backups: (backups || {}).limit,
snapshots: (snapshots || {}).limit,
server_groups: (server_groups || {}).limit,
server_group_members: (server_group_members || {}).limit,
endpoint_group: (endpoint_group || {}).limit,
loadbalancer: (loadbalancer || {}).limit,
};
// eslint-disable-next-line no-return-assign
this.volumeTypesData.forEach((i) => {
initData[i.key] = this.store.quota[i.key].limit;
});
this.formRef.current.setFieldsValue(initData);
}
return {};
const { quota = {} } = this.projectStore;
const initData = {};
Object.keys(quota).forEach((key) => {
const item = this.formItems.find((it) => it.name === key);
if (item) {
const { limit } = quota[key] || {};
initData[key] = limit;
}
});
return initData;
}
// static allowed = item => Promise.resolve(true);
checkMin = (rule, value) => {
const { quota } = this.store;
const { quota } = this.projectStore;
const { field } = rule;
const { used } = quota[field];
const intNum = /^-?\d+$/;
@ -169,205 +91,107 @@ export class QuotaManager extends ModalAction {
return Promise.resolve();
};
get formItems() {
getTitleLabel = (name, title, hidden) => {
const content = (
<div style={{ textAlign: 'center', fontWeight: 'bolder' }}>{title}</div>
);
return {
name,
label: '',
type: 'label',
content,
wrapperCol: { span: 24 },
hidden,
};
};
getInputItem(name, label, hidden) {
return {
name,
label,
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
hidden,
};
}
get quotaCardList() {
return quotaCardList;
}
getFormItemsByCards(cardType) {
const card = this.quotaCardList.find((it) => it.type === cardType);
if (!card) {
return [];
}
const { type, text, value } = card;
const labelItem = this.getTitleLabel(type, text);
const items = value.map((it) => {
const { key, text: vText } = it;
return this.getInputItem(key, vText);
});
return [labelItem, ...items];
}
getComputeFormItems() {
const formItems = this.getFormItemsByCards('compute');
const memberItem = this.getInputItem(
'server_group_members',
t('Server Group Member')
);
return [...formItems, memberItem];
}
get volumeTypeData() {
const { projectVolumeTypes: data = [] } = this.volumeTypeStore;
return data;
}
getVolumeTypeFormItems() {
const { more } = this.state;
const card = getVolumeTypeCards(this.volumeTypeData);
const { type, text, value } = card;
const newValue = [];
value.forEach((it) => newValue.push(...it.value));
const labelItem = this.getTitleLabel(type, text, !more);
const items = newValue.map((it) =>
this.getInputItem(it.key, it.text, !more)
);
return [labelItem, ...items];
}
get formItems() {
const computeFormItems = this.getComputeFormItems();
const cinderFormItems = this.getFormItemsByCards('storage');
const networkFormItems = this.getFormItemsByCards('networks');
const volumeTypeFormItems = this.getVolumeTypeFormItems();
const form = [
{
name: 'nova',
label: t('Compute'),
type: 'label',
labelCol: { span: 12, offset: 6 },
},
{
name: 'instances',
label: t('instance'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'cores',
label: t('vCPU'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'ram',
label: t('RAM(GB)'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'key_pairs',
label: t('keypair'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'server_groups',
label: t('Server Group'),
type: 'input-number',
labelCol: { span: 6 },
validator: this.checkMin,
},
{
name: 'server_group_members',
label: t('Server Group Member'),
type: 'input-number',
labelCol: { span: 6 },
validator: this.checkMin,
},
{
name: 'cinder',
label: t('Storage'),
type: 'label',
labelCol: { span: 12, offset: 6 },
colNum: 2,
},
{
name: 'networks',
label: t('Network'),
type: 'label',
labelCol: { span: 12, offset: 6 },
colNum: 2,
},
{
name: 'volumes',
label: t('Volume'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'router',
label: t('router'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'gigabytes',
label: `${t('gigabytes')}(GB)`,
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'network',
label: t('network'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'backups',
label: t('Backup'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'subnet',
label: t('subnet'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'backup_gigabytes',
label: t('Backup Capacity'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'floatingip',
label: t('floatingip'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'snapshots',
label: t('Snapshot'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'port',
label: t('Port'),
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
validator: this.checkMin,
},
{
name: 'security_group',
label: t('security_group'),
type: 'input-number',
labelCol: { span: 6, offset: 12 },
validator: this.checkMin,
},
{
name: 'security_group_rule',
label: t('Security Group Rules'),
type: 'input-number',
labelCol: { span: 6, offset: 12 },
validator: this.checkMin,
},
...computeFormItems,
...cinderFormItems,
...networkFormItems,
{
name: 'more',
label: t('Advanced Options'),
type: 'more',
},
{
name: 'cinder_types',
label: t('Storage Types'),
type: 'label',
labelCol: { span: 21, offset: 3 },
hidden: !more,
},
...volumeTypeFormItems,
];
this.volumeTypesData.forEach((i) =>
form.push({
name: i.key,
label: i.text,
type: 'input-number',
labelCol: { span: 12 },
colNum: 2,
hidden: !more,
validator: this.checkMin,
})
);
return form;
}
onSubmit = async (values) => {
getSubmitData(values) {
const { id: project_id } = this.item;
const { more, cinder, networks, cinder_types, nova, security, ...others } =
values;
const results = this.store.updateProjectQuota({
const { more, compute, storage, networks, volumeTypes, ...others } = values;
return {
project_id,
data: others,
});
};
}
onSubmit = async (body) => {
const results = this.store.updateProjectQuota(body);
return results;
};
}

View File

@ -62,18 +62,7 @@ export class ProjectStore extends Base {
return client.neutron.quotas;
}
@action
async fetchList({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
// const params = { ...filters };
async fetchProjects(filters) {
const { tags } = filters;
const [roleAssignmentsReault, projectsResult, roleResult] =
@ -111,11 +100,25 @@ export class ProjectStore extends Base {
project.group_num = Object.keys(projectGroups).length;
return project;
});
const items = projects.map(this.mapper);
const newData = await this.listDidFetch(items);
return projects;
}
@action
async fetchList({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const items = await this.fetchProjects(filters);
const data = await this.listDidFetch(items, true, filters);
const newData = data.map(this.mapper);
this.list.update({
data: newData,
total: projects.length || 0,
total: newData.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
@ -124,7 +127,7 @@ export class ProjectStore extends Base {
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return projects;
return items;
}
@action
@ -212,11 +215,7 @@ export class ProjectStore extends Base {
return this.submitting(this.client.create(reqBody));
}
@action
async fetchDetail({ id, silent }) {
if (!silent) {
this.isLoading = true;
}
async fetchProject(id) {
const [roleAssignmentsReault, projectResult, roleResult] =
await Promise.all([
this.roleAssignmentClient.list(),
@ -250,11 +249,21 @@ export class ProjectStore extends Base {
project.user_num = Object.keys(userMapRole).length;
project.group_num = Object.keys(projectGroups).length;
const newItem = await this.detailDidFetch(project);
this.detail = newItem;
this.isLoading = false;
return newItem;
}
@action
async fetchDetail({ id, silent }) {
if (!silent) {
this.isLoading = true;
}
const item = await this.fetchProject(id);
const detail = this.mapper(item);
this.detail = detail;
this.isLoading = false;
return detail;
}
@action
async edit({ id, description, name }) {
const reqBody = {
@ -287,6 +296,7 @@ export class ProjectStore extends Base {
}
});
this.quota = quota;
return quota;
}
omitNil = (obj) => {
@ -298,30 +308,14 @@ export class ProjectStore extends Base {
}, {});
};
@action
async updateProjectQuota({ project_id, data }) {
this.isSubmitting = true;
getNovaQuotaBody(data) {
const {
instances,
cores,
ram,
volumes,
gigabytes,
firewall_group,
security_group_rule,
server_groups,
snapshots,
backups,
backup_gigabytes,
network,
router,
subnet,
floatingip,
security_group,
port,
server_group_members,
key_pairs,
...others
} = data;
let ramGb = ram;
if (ram && ram !== -1) {
@ -337,17 +331,40 @@ export class ProjectStore extends Base {
key_pairs,
}),
};
return novaReqBody;
}
getCinderQuotaBody(data) {
const { backups, ...others } = data;
const rest = {};
Object.keys(others).forEach((key) => {
if (
key.includes('volumes') ||
key.includes('gigabytes') ||
key.includes('snapshots')
) {
rest[key] = others[key];
}
});
const cinderReqBody = {
quota_set: this.omitNil({
volumes,
gigabytes,
backup_gigabytes,
snapshots,
backups,
...others,
...rest,
}),
};
const firewallValue = firewall_group ? { firewall_group } : {};
return cinderReqBody;
}
getNeutronQuotaBody(data) {
const {
security_group_rule,
network,
router,
subnet,
floatingip,
security_group,
port,
} = data;
const neutronReqBody = {
quota: this.omitNil({
network,
@ -356,10 +373,16 @@ export class ProjectStore extends Base {
floatingip,
security_group,
security_group_rule,
...firewallValue,
port,
}),
};
return neutronReqBody;
}
async updateQuota(project_id, data) {
const novaReqBody = this.getNovaQuotaBody(data);
const cinderReqBody = this.getCinderQuotaBody(data);
const neutronReqBody = this.getNeutronQuotaBody(data);
const reqs = [];
if (!isEmpty(novaReqBody.quota_set)) {
reqs.push(client.nova.quotaSets.update(project_id, novaReqBody));
@ -372,6 +395,13 @@ export class ProjectStore extends Base {
}
const result = await Promise.all(reqs);
return result;
}
@action
async updateProjectQuota({ project_id, data }) {
this.isSubmitting = true;
const result = await this.updateQuota(project_id, data);
this.isSubmitting = false;
return result;
}
@ -461,7 +491,6 @@ export class ProjectStore extends Base {
}
groupResult.groups.forEach((group) => {
if (projectGroups[group.id]) {
// const id = 3;
project.groupProjectRole = projectGroups[group.id].map(
(it) =>
`${roleResult.roles.filter((role) => role.id === it)[0].name}(${t(
@ -470,8 +499,6 @@ export class ProjectStore extends Base {
);
}
});
// const { id } = project;
// this.getUserRoleList({ id, user_id: userId });
project.user_num = Object.keys(userMapRole).length;
project.group_num = Object.keys(projectGroups).length;
return project;