feat: support quota info when create key pair
1. Support quota info when create key pair 2. Disable click submit button when user's key pairs exceed project key pair quota 3. Update Ring component to add tooltip when quota is unlimit, better impression quantity information 4. Update Ring component to support left quota < 0 situation 5. Add quota tip in create key pair form for better understander the quota of key pair Change-Id: I31282db5a9a3c35c4e3f904df96689b52149b2ec
This commit is contained in:
parent
55e0abab85
commit
b22a959e49
@ -22,6 +22,7 @@ import {
|
||||
Annotation,
|
||||
Tooltip,
|
||||
} from 'bizcharts';
|
||||
import { Tooltip as AntTooltip } from 'antd';
|
||||
|
||||
export const typeColors = {
|
||||
used: '#5B8FF9',
|
||||
@ -59,7 +60,10 @@ export default function Ring(props) {
|
||||
const showTip = isLimit;
|
||||
const limitNumber = !isLimit ? Infinity : limit;
|
||||
const limitStr = !isLimit ? t('Infinity') : limit;
|
||||
const left = !isLimit ? 1 : limit - used - reserved - add;
|
||||
let left = !isLimit ? 1 : limit - used - reserved - add;
|
||||
if (left < 0) {
|
||||
left = 0;
|
||||
}
|
||||
const data = [
|
||||
{
|
||||
type: t('Used'),
|
||||
@ -93,53 +97,71 @@ export default function Ring(props) {
|
||||
const allCount = used + add + reserved;
|
||||
const percent = isLimit ? (allCount / limitNumber) * 100 : 0;
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
<Chart placeholder={false} height={height} padding="auto" autoFit>
|
||||
<Legend visible={showTip && hasLabel} />
|
||||
<Tooltip visible={showTip} />
|
||||
{/* 绘制图形 */}
|
||||
<View data={data}>
|
||||
<Coordinate type="theta" innerRadius={0.75} />
|
||||
<Interval
|
||||
position="value"
|
||||
adjust="stack"
|
||||
color={['type', colors]}
|
||||
size={16}
|
||||
/>
|
||||
<Annotation.Text
|
||||
position={['50%', '30%']}
|
||||
content={title}
|
||||
style={{
|
||||
lineHeight: '240px',
|
||||
fontSize: '14',
|
||||
fill: '#000',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
/>
|
||||
<Annotation.Text
|
||||
position={['50%', '50%']}
|
||||
content={secondTitle}
|
||||
style={{
|
||||
lineHeight: '240px',
|
||||
fontSize: '14',
|
||||
fill: '#000',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
/>
|
||||
<Annotation.Text
|
||||
position={['50%', '70%']}
|
||||
content={`${allCount}/${limitStr}`}
|
||||
style={{
|
||||
lineHeight: '240px',
|
||||
fontSize: '14',
|
||||
fill: getUsedValueColor(percent),
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</Chart>
|
||||
</div>
|
||||
let tipTitle = '';
|
||||
if (!isLimit) {
|
||||
const usedTip = `${t('Used')}: ${used}`;
|
||||
const reservedTip = reserved ? '' : `${t('Reserved')}: ${reserved}`;
|
||||
const newTip = `${t('New')}: ${add}`;
|
||||
const tips = [usedTip, newTip];
|
||||
if (reserved) {
|
||||
tips.splice(1, 0, reservedTip);
|
||||
}
|
||||
tipTitle = tips.join(' / ');
|
||||
}
|
||||
|
||||
const chart = (
|
||||
<Chart placeholder={false} height={height} padding="auto" autoFit>
|
||||
<Legend visible={showTip && hasLabel} />
|
||||
<Tooltip visible={showTip} />
|
||||
{/* 绘制图形 */}
|
||||
<View data={data}>
|
||||
<Coordinate type="theta" innerRadius={0.75} />
|
||||
<Interval
|
||||
position="value"
|
||||
adjust="stack"
|
||||
color={['type', colors]}
|
||||
size={16}
|
||||
/>
|
||||
<Annotation.Text
|
||||
position={['50%', '30%']}
|
||||
content={title}
|
||||
style={{
|
||||
lineHeight: '240px',
|
||||
fontSize: '14',
|
||||
fill: '#000',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
/>
|
||||
<Annotation.Text
|
||||
position={['50%', '50%']}
|
||||
content={secondTitle}
|
||||
style={{
|
||||
lineHeight: '240px',
|
||||
fontSize: '14',
|
||||
fill: '#000',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
/>
|
||||
<Annotation.Text
|
||||
position={['50%', '70%']}
|
||||
content={`${allCount}/${limitStr}`}
|
||||
style={{
|
||||
lineHeight: '240px',
|
||||
fontSize: '14',
|
||||
fill: getUsedValueColor(percent),
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</Chart>
|
||||
);
|
||||
|
||||
const content = isLimit ? (
|
||||
chart
|
||||
) : (
|
||||
<AntTooltip title={tipTitle}>{chart}</AntTooltip>
|
||||
);
|
||||
|
||||
return <div style={style}>{content}</div>;
|
||||
}
|
||||
|
@ -1812,6 +1812,7 @@
|
||||
"Quota exceeded": "Quota exceeded",
|
||||
"Quota is not enough for extend share.": "Quota is not enough for extend share.",
|
||||
"Quota is not enough for extend volume.": "Quota is not enough for extend volume.",
|
||||
"Quota of key pair means: the number of allowed key pairs for each user.": "Quota of key pair means: the number of allowed key pairs for each user.",
|
||||
"Quota: Insufficient quota to create resources, please adjust resource quantity or quota(left { quota }, input { input }).": "Quota: Insufficient quota to create resources, please adjust resource quantity or quota(left { quota }, input { input }).",
|
||||
"Quota: Insufficient { name } quota to create resources, please adjust resource quantity or quota(left { left }, input { input }).": "Quota: Insufficient { name } quota to create resources, please adjust resource quantity or quota(left { left }, input { input }).",
|
||||
"Quota: Project quotas sufficient resources can be created": "Quota: Project quotas sufficient resources can be created",
|
||||
|
@ -1812,6 +1812,7 @@
|
||||
"Quota exceeded": "配额用尽",
|
||||
"Quota is not enough for extend share.": "配额不足以扩容共享。",
|
||||
"Quota is not enough for extend volume.": "配额不足以扩容云硬盘。",
|
||||
"Quota of key pair means: the number of allowed key pairs for each user.": "密钥的配额表示:每个用户允许创建的密钥数量。",
|
||||
"Quota: Insufficient quota to create resources, please adjust resource quantity or quota(left { quota }, input { input }).": "配额:项目配额不足,无法创建资源,请进行资源数量或配额的调整(剩余{ quota },输入{ input })。",
|
||||
"Quota: Insufficient { name } quota to create resources, please adjust resource quantity or quota(left { left }, input { input }).": "配额:{ name } 配额不足,无法创建资源,请进行资源数量或配额的调整(剩余{ left },输入{ input })。",
|
||||
"Quota: Project quotas sufficient resources can be created": "配额:项目配额充足,可创建资源",
|
||||
@ -2241,7 +2242,7 @@
|
||||
"The name should start with upper letter, lower letter, and be a string of 3 to 63, characters can only contain \"0-9, a-z, A-Z, -\".": "名称应以大写字母,小写字母开头,长度为3-63字符,且只包含“0-9, a-z, A-Z, -”。",
|
||||
"The new password cannot be identical to the current password.": "用户新密码不能与原密码相同。",
|
||||
"The no_proxy address to use for nodes in cluster": "用于集群中节点的 no_proxy 地址",
|
||||
"The number of allowed key pairs for each user.": "每个用户允许创建的配额数量",
|
||||
"The number of allowed key pairs for each user.": "每个用户允许创建的密钥数量",
|
||||
"The number of vCPU cores should not exceed the maximum number of CPU cores of the physical node. Otherwise it will cause fail to schedule to any physical node when creating instance.": "vCPU核数不应该超过物理节点的最大CPU核数,否则会导致云主机创建时无法调度到任何物理节点。",
|
||||
"The number of virtual cpu for this container": "容器的虚拟 CPU 数量",
|
||||
"The password must not be the same as the previous": "新密码不能与以前的密码相同",
|
||||
|
@ -31,10 +31,7 @@ const colors = {
|
||||
const keyPairTitle = (
|
||||
<span>
|
||||
{t('Key Pair')}
|
||||
<Tooltip
|
||||
title={t('The number of allowed key pairs for each user.')}
|
||||
getPopupContainer={(node) => node.parentNode}
|
||||
>
|
||||
<Tooltip title={t('The number of allowed key pairs for each user.')}>
|
||||
<QuestionCircleOutlined style={{ marginLeft: 4 }} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
@ -15,8 +15,23 @@
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import { ModalAction } from 'containers/Action';
|
||||
import globalKeypairStore from 'stores/nova/keypair';
|
||||
import globalProjectStore from 'stores/keystone/project';
|
||||
import FileSaver from 'file-saver';
|
||||
|
||||
const getUsed = () => {
|
||||
const { total = 0, data = [] } = globalKeypairStore.list || {};
|
||||
return total || data.length;
|
||||
};
|
||||
|
||||
const getAdd = (quota) => {
|
||||
const { limit = 0 } = quota || {};
|
||||
if (limit === -1) {
|
||||
return 1;
|
||||
}
|
||||
const used = getUsed();
|
||||
return limit > used ? 1 : 0;
|
||||
};
|
||||
|
||||
export class CreateKeypair extends ModalAction {
|
||||
static id = 'create-keypair';
|
||||
|
||||
@ -26,6 +41,64 @@ export class CreateKeypair extends ModalAction {
|
||||
return t('Create Keypair');
|
||||
}
|
||||
|
||||
init() {
|
||||
this.state.quota = {};
|
||||
this.state.quotaLoading = true;
|
||||
this.projectStore = globalProjectStore;
|
||||
this.getQuota();
|
||||
}
|
||||
|
||||
get tips() {
|
||||
return t(
|
||||
'Quota of key pair means: the number of allowed key pairs for each user.'
|
||||
);
|
||||
}
|
||||
|
||||
static get disableSubmit() {
|
||||
const {
|
||||
novaQuota: { key_pairs: quota = {} },
|
||||
} = globalProjectStore;
|
||||
const add = getAdd(quota);
|
||||
return add === 0;
|
||||
}
|
||||
|
||||
static get showQuota() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get showQuota() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async getQuota() {
|
||||
this.setState({
|
||||
quotaLoading: true,
|
||||
});
|
||||
const result = await this.projectStore.fetchProjectNovaQuota();
|
||||
const { key_pairs: quota = {} } = result || {};
|
||||
this.setState({
|
||||
quota,
|
||||
quotaLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
get quotaInfo() {
|
||||
const { quota = {}, quotaLoading } = this.state;
|
||||
if (quotaLoading) {
|
||||
return [];
|
||||
}
|
||||
const add = getAdd(quota);
|
||||
const used = getUsed();
|
||||
const data = {
|
||||
...quota,
|
||||
add,
|
||||
used,
|
||||
name: 'key_pair',
|
||||
title: t('Key Pair'),
|
||||
};
|
||||
return [data];
|
||||
}
|
||||
|
||||
onSubmit = (values) => {
|
||||
const { name, public_key } = values;
|
||||
const params = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user