refactor: Refactor project detail quota codes
1. Refactor project quota in project detail page 2. Add keypair quota display in overview/project detail quota page Change-Id: I40e5925909d767a87eadd09cfb9c11ea1624cead
This commit is contained in:
parent
e182d62b34
commit
ae266d3d74
@ -885,6 +885,7 @@
|
||||
"Kernel ID": "Kernel ID",
|
||||
"Kernel Image": "Kernel Image",
|
||||
"Key": "Key",
|
||||
"Key Pair": "Key Pair",
|
||||
"Key Pairs": "Key Pairs",
|
||||
"Key Size (bits)": "Key Size (bits)",
|
||||
"Keypair": "Keypair",
|
||||
@ -1791,7 +1792,6 @@
|
||||
"compute hosts": "compute hosts",
|
||||
"compute services": "compute services",
|
||||
"connect subnet": "connect subnet",
|
||||
"core": "core",
|
||||
"create DSCP marking rule": "create DSCP marking rule",
|
||||
"create a new network/subnet": "create a new network/subnet",
|
||||
"create a new security group": "create a new security group",
|
||||
@ -1925,7 +1925,6 @@
|
||||
"qoS policy": "qoS policy",
|
||||
"qos specs": "qos specs",
|
||||
"quota set to -1 means there is no quota limit on the current resource": "quota set to -1 means there is no quota limit on the current resource",
|
||||
"ram": "ram",
|
||||
"reboot instance": "reboot instance",
|
||||
"rebuild instance": "rebuild instance",
|
||||
"recover instance": "recover instance",
|
||||
|
@ -885,6 +885,7 @@
|
||||
"Kernel ID": "内核ID",
|
||||
"Kernel Image": "Kernel镜像",
|
||||
"Key": "键",
|
||||
"Key Pair": "密钥",
|
||||
"Key Pairs": "密钥",
|
||||
"Key Size (bits)": "密钥大小(比特)",
|
||||
"Keypair": "SSH密钥对",
|
||||
@ -1791,7 +1792,6 @@
|
||||
"compute hosts": "计算节点",
|
||||
"compute services": "计算服务",
|
||||
"connect subnet": "连接子网",
|
||||
"core": "虚拟CPU",
|
||||
"create DSCP marking rule": "创建DSCP标记规则",
|
||||
"create a new network/subnet": "新建网络/子网",
|
||||
"create a new security group": "新建安全组",
|
||||
@ -1925,7 +1925,6 @@
|
||||
"qoS policy": "QoS策略",
|
||||
"qos specs": "QoS规格",
|
||||
"quota set to -1 means there is no quota limit on the current resource": "配额为设为 -1 时表示当前资源无配额限制",
|
||||
"ram": "内存(GB)",
|
||||
"reboot instance": "重启云主机",
|
||||
"rebuild instance": "重建云主机",
|
||||
"recover instance": "恢复云主机",
|
||||
|
@ -16,7 +16,6 @@ import React, { Component } from 'react';
|
||||
import { Badge, Card, Col, List, Progress, Row, Spin, Tooltip } from 'antd';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import globalVolumeTypeStore from 'stores/cinder/volume-type';
|
||||
import globalKeypairStore from 'stores/nova/keypair';
|
||||
import globalProjectStore from 'stores/keystone/project';
|
||||
import { isNumber } from 'lodash';
|
||||
import styles from '../style.less';
|
||||
@ -36,6 +35,7 @@ export const quotaCardList = [
|
||||
{ text: t('vCPUs'), key: 'cores' },
|
||||
{ text: t('Memory'), key: 'ram' },
|
||||
{ text: t('Server Group'), key: 'server_groups' },
|
||||
{ text: t('Key Pair'), key: 'key_pairs' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -85,6 +85,9 @@ export class QuotaOverview extends Component {
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
};
|
||||
const { projectStore, volumeTypeStore } = props;
|
||||
this.projectStore = projectStore || globalProjectStore;
|
||||
this.volumeTypeStore = volumeTypeStore || globalVolumeTypeStore;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -92,20 +95,29 @@ export class QuotaOverview extends Component {
|
||||
}
|
||||
|
||||
async getData() {
|
||||
const { user } = this.props.rootStore;
|
||||
const { project: { id: projectId = '' } = {} } = user;
|
||||
await Promise.all([
|
||||
globalProjectStore.fetchProjectQuota({ project_id: projectId }),
|
||||
globalVolumeTypeStore.fetchList(),
|
||||
globalKeypairStore.fetchList(),
|
||||
]);
|
||||
const { getData } = this.props;
|
||||
if (getData) {
|
||||
await getData();
|
||||
} else {
|
||||
const { user } = this.props.rootStore;
|
||||
const { project: { id: projectId = '' } = {} } = user;
|
||||
await Promise.all([
|
||||
this.projectStore.fetchProjectQuota({ project_id: projectId }),
|
||||
this.volumeTypeStore.fetchList(),
|
||||
]);
|
||||
}
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
get volumeTypeData() {
|
||||
const { volumeTypeData } = this.props;
|
||||
return volumeTypeData || this.volumeTypeStore.list.data;
|
||||
}
|
||||
|
||||
get volumeTypesQuota() {
|
||||
const volumeTypes = globalVolumeTypeStore.list.data.map((item, index) => {
|
||||
const volumeTypes = this.volumeTypeData.map((item, index) => {
|
||||
return {
|
||||
index,
|
||||
value: [
|
||||
@ -211,7 +223,7 @@ export class QuotaOverview extends Component {
|
||||
return <Spin />;
|
||||
}
|
||||
return this.renderQuotaCart(
|
||||
globalProjectStore.quota,
|
||||
this.projectStore.quota,
|
||||
this.getFilteredValue(item.value)
|
||||
);
|
||||
}
|
||||
@ -238,7 +250,7 @@ export class QuotaOverview extends Component {
|
||||
<Row key={item.index} gutter={[16]}>
|
||||
{item.value.map((i) => (
|
||||
<Col span={8} key={i.text}>
|
||||
{this.getItemInfo(globalProjectStore.quota, i)}
|
||||
{this.getItemInfo(this.projectStore.quota, i)}
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
|
@ -55,72 +55,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
//margin: 16px 0;
|
||||
|
||||
:global {
|
||||
.ant-card {
|
||||
box-shadow: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
.text {
|
||||
font-size: 16px;
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-left: 22px;
|
||||
|
||||
:global {
|
||||
.ant-badge-status-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.ant-badge-status-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
font-size: 12px;
|
||||
color: #0068ff;
|
||||
float: right;
|
||||
margin-top: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content {
|
||||
.card {
|
||||
padding: 8px;
|
||||
|
||||
:global {
|
||||
.ant-card-head {
|
||||
border-bottom: none;
|
||||
|
||||
.ant-card-head-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #565656;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress_title {
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
@ -176,3 +110,69 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
//margin: 16px 0;
|
||||
|
||||
:global {
|
||||
.ant-card {
|
||||
box-shadow: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
.text {
|
||||
font-size: 16px;
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-left: 22px;
|
||||
|
||||
:global {
|
||||
.ant-badge-status-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.ant-badge-status-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
font-size: 12px;
|
||||
color: #0068ff;
|
||||
float: right;
|
||||
margin-top: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content {
|
||||
.card {
|
||||
padding: 8px;
|
||||
|
||||
:global {
|
||||
.ant-card-head {
|
||||
border-bottom: none;
|
||||
|
||||
.ant-card-head-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #565656;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress_title {
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,180 +12,43 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import { observer, inject } from 'mobx-react';
|
||||
|
||||
import globalProjectStore from 'stores/keystone/project';
|
||||
import { Card, Col, Row, List } from 'antd';
|
||||
import Progress from 'components/ProjectProgress';
|
||||
import classnames from 'classnames';
|
||||
import React, { Component } from 'react';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import QuotaOverview from 'pages/base/containers/Overview/components/QuotaOverview';
|
||||
import { VolumeTypeStore } from 'stores/cinder/volume-type';
|
||||
import { ProjectStore } from 'stores/keystone/project';
|
||||
import styles from './index.less';
|
||||
|
||||
export class Quota extends React.Component {
|
||||
export class Quota extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
this.init();
|
||||
this.projectStore = new ProjectStore();
|
||||
this.volumeTypeStore = new VolumeTypeStore();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getData();
|
||||
get volumeTypeData() {
|
||||
return this.volumeTypeStore.projectVolumeTypes;
|
||||
}
|
||||
|
||||
getData = async () => {
|
||||
const { id: project_id } = this.props.match.params;
|
||||
await this.store.fetchProjectQuota({
|
||||
project_id,
|
||||
});
|
||||
await this.volumeTypeStore.fetchProjectVolumeTypes(project_id);
|
||||
return Promise.all([
|
||||
this.projectStore.fetchProjectQuota({
|
||||
project_id,
|
||||
}),
|
||||
this.volumeTypeStore.fetchProjectVolumeTypes(project_id),
|
||||
]);
|
||||
};
|
||||
|
||||
getItemInfo = (i) => {
|
||||
const { quota } = this.store;
|
||||
const resource = quota[i.key];
|
||||
return <Progress resource={resource} name={i.text} nameSpan={8} />;
|
||||
};
|
||||
|
||||
init() {
|
||||
this.store = globalProjectStore;
|
||||
this.volumeTypeStore = new VolumeTypeStore();
|
||||
}
|
||||
|
||||
renderVolumeTypes = (listData) => (
|
||||
<List
|
||||
itemLayout="vertical"
|
||||
size="large"
|
||||
pagination={{
|
||||
hideOnSinglePage: true,
|
||||
pageSize: 5,
|
||||
size: 'small',
|
||||
}}
|
||||
dataSource={listData}
|
||||
renderItem={(item) => (
|
||||
<Row key={item.index} gutter={[16]}>
|
||||
{item.value.map((i) => (
|
||||
<Col span={8} key={i.text}>
|
||||
{this.getItemInfo(i)}
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
render() {
|
||||
const { quota } = this.store;
|
||||
const volumeTypes = [];
|
||||
this.volumeTypeStore.projectVolumeTypes.forEach((item, index) => {
|
||||
volumeTypes.push({
|
||||
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 (
|
||||
<div className={classnames(styles.wrapper, this.className)}>
|
||||
<Card>
|
||||
{quota.instances ? (
|
||||
<div>
|
||||
<Row>
|
||||
<Col xs={{ span: 8, offset: 1 }} lg={{ span: 8 }}>
|
||||
<div style={{ fontSize: 16, marginBottom: 12 }}>
|
||||
{t('Compute')}
|
||||
</div>
|
||||
<Progress resource={quota.instances} name={t('instance')} />
|
||||
<Progress resource={quota.cores} name={t('core')} />
|
||||
<Progress resource={quota.ram} name={t('ram')} />
|
||||
{/* <Progress resource={quota.key_pairs} name={t('keypair')} /> */}
|
||||
<div>
|
||||
<p style={{ float: 'right' }}>
|
||||
( {t('Member in group')} :{' '}
|
||||
{quota.server_group_members &&
|
||||
quota.server_group_members.limit === -1
|
||||
? t('Unlimit')
|
||||
: quota.server_group_members.limit}{' '}
|
||||
)
|
||||
</p>
|
||||
<Progress
|
||||
resource={quota.server_groups}
|
||||
name={t('Server Group')}
|
||||
/>
|
||||
</div>
|
||||
{/* <Progress resource={quota.server_group_members} name={t('Server Group Member')} /> */}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
) : null}
|
||||
{quota.volumes ? (
|
||||
<div>
|
||||
<Row style={{ marginTop: 30 }}>
|
||||
<Col xs={{ span: 8, offset: 1 }} lg={{ span: 8 }}>
|
||||
<div style={{ fontSize: 16, marginBottom: 12 }}>
|
||||
{t('Storage')}
|
||||
</div>
|
||||
<Progress name={t('Volume')} resource={quota.volumes} />
|
||||
<Progress
|
||||
name={`${t('gigabytes')}(GB)`}
|
||||
resource={quota.gigabytes}
|
||||
/>
|
||||
<Progress name={t('backups')} resource={quota.backups} />
|
||||
<Progress
|
||||
name={t('Backup Capacity')}
|
||||
resource={quota.backup_gigabytes}
|
||||
/>
|
||||
<Progress name={t('Snapshot')} resource={quota.snapshots} />
|
||||
</Col>
|
||||
<Col xs={{ span: 8, offset: 1 }} lg={{ span: 8, offset: 6 }}>
|
||||
<div style={{ fontSize: 16, marginBottom: 12 }}>
|
||||
{t('Network')}
|
||||
</div>
|
||||
<Progress resource={quota.router} name={t('router')} />
|
||||
<Progress resource={quota.network} name={t('network')} />
|
||||
<Progress resource={quota.subnet} name={t('subnet')} />
|
||||
<Progress
|
||||
resource={quota.floatingip}
|
||||
name={t('floatingip')}
|
||||
/>
|
||||
<Progress resource={quota.port} name={t('port')} />
|
||||
<Progress
|
||||
name={t('security_group')}
|
||||
resource={quota.security_group}
|
||||
/>
|
||||
<Progress
|
||||
name={t('Security Group Rule')}
|
||||
resource={quota.security_group_rule}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
) : null}
|
||||
{volumeTypes[0] ? (
|
||||
<div>
|
||||
<Row style={{ marginTop: 30 }}>
|
||||
<Col xs={{ span: 22, offset: 1 }} lg={{ span: 22 }}>
|
||||
<div style={{ fontSize: 16, marginBottom: 12 }}>
|
||||
{t('Storage Types')}
|
||||
</div>
|
||||
{this.renderVolumeTypes(volumeTypes)}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
) : null}
|
||||
</Card>
|
||||
<div className={styles.wrapper}>
|
||||
<QuotaOverview
|
||||
getData={this.getData}
|
||||
projectStore={this.projectStore}
|
||||
volumeTypeStore={this.volumeTypeStore}
|
||||
volumeTypeData={this.volumeTypeData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,5 +2,5 @@
|
||||
|
||||
.wrapper {
|
||||
min-height: calc(100vh - 108px);
|
||||
padding: 0 @body-padding;
|
||||
padding: 0 @body-padding @body-padding @body-padding;
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
@import '~antd/lib/style/themes/default.less';
|
||||
|
||||
.container {
|
||||
height: 100%;
|
||||
padding: 16px 12px;
|
||||
overflow: auto;
|
||||
|
||||
:global {
|
||||
.ant-card {
|
||||
box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.09);
|
||||
}
|
||||
}
|
||||
|
||||
.left {
|
||||
height: 100%;
|
||||
|
||||
.top {
|
||||
|
||||
.title {
|
||||
display: table-cell;
|
||||
vertical-align: bottom;
|
||||
|
||||
.text {
|
||||
font-size: 21px;
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
.action {
|
||||
font-size: 16px;
|
||||
color: #000000;
|
||||
margin-left: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
margin: 16px 0;
|
||||
|
||||
:global {
|
||||
.ant-card {
|
||||
box-shadow: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
.text {
|
||||
font-size: 16px;
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-left: 22px;
|
||||
|
||||
:global {
|
||||
.ant-badge-status-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.ant-badge-status-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
font-size: 12px;
|
||||
color: #0068FF;
|
||||
float: right;
|
||||
margin-top: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.card {
|
||||
padding: 8px;
|
||||
|
||||
:global {
|
||||
.ant-card-head {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.progress_title {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
height: 100%;
|
||||
|
||||
.top {
|
||||
.meta {
|
||||
padding-bottom: 16px;
|
||||
margin-bottom: 16px;
|
||||
border-bottom: 1px dashed #e8e8e8;
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-descriptions-item-label {
|
||||
width: 130px;
|
||||
}
|
||||
}
|
||||
|
||||
.money {
|
||||
color: #0068FF;
|
||||
line-height: 42px;
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.middle {
|
||||
margin-top: 1.33rem;
|
||||
background-color: #ffffff;
|
||||
|
||||
.row {
|
||||
text-align: center;
|
||||
|
||||
.alert_value {
|
||||
font-size: 56px;
|
||||
}
|
||||
|
||||
.alert_key {
|
||||
color: #252525;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
margin-top: 1.33rem;
|
||||
background-color: #ffffff;
|
||||
|
||||
.timeline {
|
||||
|
||||
.time {
|
||||
font-size: 14px;
|
||||
color: #0068FF;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.bulletin {
|
||||
font-size: 14px;
|
||||
color: #252525;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-card-head {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user