From a82cd5883d2377349fc77ab009dd13f3b60948c7 Mon Sep 17 00:00:00 2001 From: "Jingwei.Zhang" Date: Thu, 30 Jun 2022 17:34:15 +0800 Subject: [PATCH] feat: support quota info when create share 1. Support quota info when create share 2. Disable click submit button when left quota is not enough to create Change-Id: I6af7cb3c29cad89dbceffb3c33d93eb46d0f963d --- .../share/containers/Share/actions/Create.jsx | 74 ++++++++++--- src/resources/manila/share.js | 103 ++++++++++++++++++ src/stores/keystone/project.js | 14 +++ src/stores/manila/share.js | 8 ++ 4 files changed, 181 insertions(+), 18 deletions(-) diff --git a/src/pages/share/containers/Share/actions/Create.jsx b/src/pages/share/containers/Share/actions/Create.jsx index 0f0c5553..f4c36906 100644 --- a/src/pages/share/containers/Share/actions/Create.jsx +++ b/src/pages/share/containers/Share/actions/Create.jsx @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { toJS } from 'mobx'; import { inject, observer } from 'mobx-react'; import { FormAction } from 'containers/Action'; import globalShareStore, { ShareStore } from 'stores/manila/share'; @@ -33,13 +32,28 @@ import { getShareNetworkColumns, shareNetworkFilters, } from 'resources/manila/share-network'; -import { shareProtocol } from 'resources/manila/share'; -import { cloneDeep } from 'lodash'; +import { + shareProtocol, + getQuota, + getQuotaInfo, + fetchShareQuota, + checkQuotaDisable, + getShareSizeInStore, + setCreateShareSize, + onShareSizeChange, +} from 'resources/manila/share'; +import { cloneDeep, isEmpty } from 'lodash'; import { idNameColumn } from 'utils/table'; import { extraFormItem } from 'pages/share/containers/ShareType/actions/Create'; import { updateAddSelectValueToObj, getOptions } from 'utils/index'; import { checkPolicyRule } from 'resources/skyline/policy'; +const quotaKeys = ['shares', 'gigabytes']; + +const getWishes = () => { + return [1, getShareSizeInStore() || 1]; +}; + export class Create extends FormAction { static id = 'create'; @@ -68,16 +82,48 @@ export class Create extends FormAction { this.shareStore.fetchAvailableZones(); this.state.showNetworks = false; this.state.shareGroups = []; + this.getQuota(); } static policy = 'manila:share:create'; static allowed = () => Promise.resolve(true); - get defaultValue() { + async getQuota() { + await fetchShareQuota(this); + setCreateShareSize(this.defaultSize); + this.updateDefaultValue(); + } + + get disableSubmit() { + const { quota, quotaLoading } = this.state; + if (isEmpty(quota) || quotaLoading) { + return true; + } + return checkQuotaDisable(quotaKeys, getWishes()); + } + + get showQuota() { + return true; + } + + getShareQuota() { + const { quota = {} } = this.state; + return getQuota(quota, quotaKeys); + } + + get quotaInfo() { + return getQuotaInfo(this, quotaKeys, getWishes()); + } + + get defaultSize() { const size = this.quotaIsLimit && this.maxSize < 10 ? this.maxSize : 10; + return size; + } + + get defaultValue() { const values = { - size, + size: this.defaultSize, project: this.currentProjectName, }; return values; @@ -101,24 +147,14 @@ export class Create extends FormAction { }); }; - get quota() { - const { shares: { limit = 10, in_use = 0, reserved = 0 } = {} } = - toJS(this.shareStore.quotaSet) || {}; - if (limit === -1) { - return Infinity; - } - return limit - in_use - reserved; - } - get quotaIsLimit() { - const { gigabytes: { limit } = {} } = toJS(this.shareStore.quotaSet) || {}; + const { gigabytes: { limit } = {} } = this.getShareQuota(); return limit !== -1; } get maxSize() { - const { gigabytes: { limit = 10, in_use = 0, reserved = 0 } = {} } = - toJS(this.shareStore.quotaSet) || {}; - return limit - in_use - reserved; + const { gigabytes: { left = 0 } = {} } = this.getShareQuota(); + return left === -1 ? 1000 : left || 1; } get shareTypeColumns() { @@ -195,6 +231,7 @@ export class Create extends FormAction { description: `${minSize}GiB-${this.maxSize}GiB`, required: this.quotaIsLimit, display: this.quotaIsLimit, + onChange: onShareSizeChange, }, { name: 'size', @@ -203,6 +240,7 @@ export class Create extends FormAction { min: minSize, display: !this.quotaIsLimit, required: !this.quotaIsLimit, + onChange: onShareSizeChange, }, { name: 'is_public', diff --git a/src/resources/manila/share.js b/src/resources/manila/share.js index bce1f73d..6760ac60 100644 --- a/src/resources/manila/share.js +++ b/src/resources/manila/share.js @@ -1,3 +1,7 @@ +import globalProjectStore from 'stores/keystone/project'; +import { isEmpty } from 'lodash'; +import globalShareStore from 'src/stores/manila/share'; + export const shareStatus = { creating: t('Creating'), creating_from_snapshot: t('Creating From Snapshot'), @@ -72,3 +76,102 @@ export const shareAccessType = { user: t('User'), cephx: t('Cephx'), }; + +// deal with quota +export function setCreateShareSize(value) { + globalShareStore.setCreateShareSize(value); +} + +export async function fetchShareQuota(self) { + self.setState({ + quota: {}, + quotaLoading: true, + }); + const result = await globalProjectStore.fetchProjectShareQuota(); + self.setState({ + quota: result, + quotaLoading: false, + }); +} + +export const getQuota = (shareQuota, quotaKeys = ['shares', 'gigabytes']) => { + if (isEmpty(shareQuota)) { + return {}; + } + return quotaKeys.reduce((pre, cur) => { + pre[cur] = shareQuota[cur] || {}; + return pre; + }, {}); +}; + +export const getAdd = ( + shareQuota, + quotaKeys = ['shares', 'gigabytes'], + wishes = [1, 1] +) => { + if (isEmpty(shareQuota)) { + return []; + } + const info = getQuota(shareQuota, quotaKeys); + let hasError = false; + quotaKeys.forEach((key, index) => { + if (!hasError) { + const quotaDetail = info[key]; + const { left = 0 } = quotaDetail || {}; + const wish = wishes[index]; + if (left !== -1 && left < wish) { + hasError = true; + } + } + }); + if (!hasError) { + return wishes; + } + return new Array(quotaKeys.length).fill(0); +}; + +const titleMap = { + shares: t('Share'), + gigabytes: t('Share Gigabytes(GiB)'), + share_networks: t('Share Network'), + share_groups: t('Share group'), +}; + +export const getQuotaInfo = ( + self, + quotaKeys = ['shares', 'gigabytes'], + wishes = [1, 1] +) => { + const { quota = {}, quotaLoading } = self.state; + if (quotaLoading || isEmpty(quota)) { + return []; + } + const adds = getAdd(quota, quotaKeys, wishes); + const infos = getQuota(quota, quotaKeys); + return quotaKeys.map((key, index) => { + const type = index === 0 ? 'ring' : 'line'; + const title = titleMap[key]; + const info = infos[key] || {}; + return { + ...info, + add: adds[index], + name: key, + title, + type, + }; + }); +}; + +export const checkQuotaDisable = (quotaKeys, wishes) => { + const { shareQuota = {} } = globalProjectStore; + const adds = getAdd(shareQuota, quotaKeys, wishes); + return adds[0] === 0; +}; + +export const onShareSizeChange = (value) => { + setCreateShareSize(value); +}; + +export const getShareSizeInStore = () => { + return globalShareStore.shareSizeForCreate; +}; diff --git a/src/stores/keystone/project.js b/src/stores/keystone/project.js index 0c8ca1bd..101a4dd1 100644 --- a/src/stores/keystone/project.js +++ b/src/stores/keystone/project.js @@ -33,6 +33,9 @@ export class ProjectStore extends Base { @observable cinderQuota = {}; + @observable + shareQuota = {}; + @observable groupRoleList = []; @@ -503,6 +506,17 @@ export class ProjectStore extends Base { this.cinderQuota = cinderQuota; return cinderQuota; } + + @action + async fetchProjectShareQuota(projectId) { + const result = await this.shareQuotaClient.showDetail( + projectId || this.currentProjectId + ); + const { quota_set: quota } = result; + const shareQuota = this.updateQuotaData(quota); + this.shareQuota = shareQuota; + return shareQuota; + } } const globalProjectStore = new ProjectStore(); diff --git a/src/stores/manila/share.js b/src/stores/manila/share.js index b5384c22..a8ced3b3 100644 --- a/src/stores/manila/share.js +++ b/src/stores/manila/share.js @@ -26,6 +26,9 @@ export class ShareStore extends Base { @observable quotaSet = {}; + @observable + shareSizeForCreate = 0; + get client() { return client.manila.shares; } @@ -168,6 +171,11 @@ export class ShareStore extends Base { @action delete = (data) => this.submitting(this.deleteItem(data)); + + @action + setCreateShareSize(size = 0) { + this.shareSizeForCreate = size; + } } const globalShareStore = new ShareStore();