mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
plugin: Quota plugin (#298)
Fixes #295 Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
30c4e3fae0
commit
b61c4ae35d
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
<slot name="name">
|
||||
<h4 class="name">
|
||||
{{ resource.displayname || resource.displaytext || resource.name || resource.hostname || resource.username || resource.ipaddress || resource.virtualmachinename }}
|
||||
{{ resource.displayname || resource.displaytext || resource.name || resource.hostname || resource.username || resource.ipaddress || resource.virtualmachinename || resource.templatetype }}
|
||||
</h4>
|
||||
<console style="margin-left: 10px" :resource="resource" size="default" v-if="resource.id" />
|
||||
</slot>
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
:loading="loading"
|
||||
:columns="fetchColumns()"
|
||||
:dataSource="items"
|
||||
:rowKey="record => record.id || record.name"
|
||||
:rowKey="record => record.id || record.name || record.usageType"
|
||||
:pagination="false"
|
||||
:rowSelection="['vm', 'event', 'alert'].includes($route.name) ? {selectedRowKeys: selectedRowKeys, onChange: onSelectChange} : null"
|
||||
:rowClassName="getRowClassName"
|
||||
@ -75,6 +75,9 @@
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
<a slot="templatetype" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
|
||||
</a>
|
||||
<a slot="displayname" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
</a>
|
||||
@ -147,11 +150,14 @@
|
||||
<router-link :to="{ path: '/pod/' + record.podid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<a slot="account" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/account/' + record.accountid }" v-if="record.accountid">{{ text }}</router-link>
|
||||
<router-link
|
||||
v-if="'quota' in record && $router.resolve(`${$route.path}/${record.account}`) !== '404'"
|
||||
:to="{ path: `${$route.path}/${record.account}`, query: { account: record.account, domainid: record.domainid, quota: true } }">{{ text }}</router-link>
|
||||
<router-link :to="{ path: '/account/' + record.accountid }" v-else-if="record.accountid">{{ text }}</router-link>
|
||||
<router-link :to="{ path: '/account', query: { name: record.account, domainid: record.domainid } }" v-else>{{ text }}</router-link>
|
||||
</a>
|
||||
<span slot="domain" slot-scope="text, record" href="javascript:;">
|
||||
<router-link v-if="record.domainid && !record.domainid.includes(',') && $router.resolve('/domain/' + record.domainid).route.name !== '404'" :to="{ path: '/domain/' + record.domainid }">{{ text }}</router-link>
|
||||
<router-link v-if="record.domainid && !record.domainid.toString().includes(',') && $router.resolve('/domain/' + record.domainid).route.name !== '404'" :to="{ path: '/domain/' + record.domainid }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</span>
|
||||
<span slot="domainpath" slot-scope="text, record" href="javascript:;">
|
||||
@ -235,6 +241,15 @@
|
||||
<a-icon type="close-circle" theme="twoTone" twoToneColor="#f5222d" />
|
||||
</a-button>
|
||||
</template>
|
||||
<template slot="tariffActions" slot-scope="text, record">
|
||||
<a-button
|
||||
shape="circle"
|
||||
v-if="editableValueKey !== record.key"
|
||||
:disabled="!('quotaTariffUpdate' in $store.getters.apis)"
|
||||
icon="edit"
|
||||
@click="editTariffValue(record)" />
|
||||
<slot></slot>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
@ -267,7 +282,7 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
inject: ['parentFetchData', 'parentToggleLoading'],
|
||||
inject: ['parentFetchData', 'parentToggleLoading', 'parentEditTariffAction'],
|
||||
data () {
|
||||
return {
|
||||
selectedRowKeys: [],
|
||||
@ -329,10 +344,9 @@ export default {
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
this.$message.error('There was an error saving this setting.')
|
||||
}).finally(() => {
|
||||
this.$emit('refresh')
|
||||
})
|
||||
.finally(() => {
|
||||
this.$emit('refresh')
|
||||
})
|
||||
},
|
||||
editValue (record) {
|
||||
this.editableValueKey = record.key
|
||||
@ -428,6 +442,9 @@ export default {
|
||||
data.forEach((item, index) => {
|
||||
this.handleUpdateOrder(item.id, index + 1)
|
||||
})
|
||||
},
|
||||
editTariffValue (record) {
|
||||
this.parentEditTariffAction(true, record)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,39 @@ export default {
|
||||
icon: 'bars',
|
||||
permission: ['quotaSummary'],
|
||||
columns: ['account', 'domain', 'state', 'currency', 'balance', 'quota'],
|
||||
details: ['account', 'domain', 'state', 'currency', 'balance', 'quota', 'startdate', 'enddate']
|
||||
details: ['account', 'domain', 'state', 'currency', 'balance', 'quota', 'startdate', 'enddate'],
|
||||
component: () => import('@/views/plugins/quota/QuotaSummary.vue'),
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
},
|
||||
{
|
||||
name: 'quota.statement.quota',
|
||||
component: () => import('@/views/plugins/quota/QuotaUsage.vue')
|
||||
},
|
||||
{
|
||||
name: 'quota.statement.balance',
|
||||
component: () => import('@/views/plugins/quota/QuotaBalance.vue')
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'quotaCredits',
|
||||
icon: 'plus',
|
||||
label: 'label.quota.add.credits',
|
||||
dataView: true,
|
||||
args: ['value', 'min_balance', 'quota_enforce'],
|
||||
mapping: {
|
||||
account: {
|
||||
value: (record) => { return record.account }
|
||||
},
|
||||
domainid: {
|
||||
value: (record) => { return record.domainid }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'quotatariff',
|
||||
@ -36,8 +68,9 @@ export default {
|
||||
icon: 'credit-card',
|
||||
docHelp: 'plugins/quota.html#quota-tariff',
|
||||
permission: ['quotaTariffList'],
|
||||
columns: ['usageName', 'description', 'usageUnit', 'tariffValue'],
|
||||
details: ['usageName', 'description', 'usageUnit', 'tariffValue']
|
||||
columns: ['usageName', 'description', 'usageUnit', 'tariffValue', 'tariffActions'],
|
||||
details: ['usageName', 'description', 'usageUnit', 'tariffValue'],
|
||||
component: () => import('@/views/plugins/quota/QuotaTariff.vue')
|
||||
},
|
||||
{
|
||||
name: 'quotaemailtemplate',
|
||||
@ -45,7 +78,11 @@ export default {
|
||||
icon: 'mail',
|
||||
permission: ['quotaEmailTemplateList'],
|
||||
columns: ['templatetype', 'templatesubject', 'templatebody'],
|
||||
details: ['templatetype', 'templatesubject', 'templatebody']
|
||||
details: ['templatetype', 'templatesubject', 'templatebody'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/views/plugins/quota/EmailTemplateDetails.vue')
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1260,6 +1260,7 @@
|
||||
"label.minmemory": "Min Memory (in MB)",
|
||||
"label.minute.past.hour": "minute(s) past the hour",
|
||||
"label.minutes.past.hour": "minutes(s) past the hour",
|
||||
"label.min_balance": "Min Balance",
|
||||
"label.monday": "Monday",
|
||||
"label.monitor": "Monitor",
|
||||
"label.monthly": "Monthly",
|
||||
@ -1530,12 +1531,14 @@
|
||||
"label.quiescevm": "Quiesce VM",
|
||||
"label.quiettime": "Quiet Time (in sec)",
|
||||
"label.quota": "Quota",
|
||||
"label.quota_enforce": "Enforce Quota",
|
||||
"label.quota.add.credits": "Add Credits",
|
||||
"label.quota.configuration": "Quota Configuration",
|
||||
"label.quota.configure": "Configure Quota",
|
||||
"label.quota.credits": "Credits",
|
||||
"label.quota.dates": "Update Dates",
|
||||
"label.quota.description": "Quota Description",
|
||||
"label.quota.email.edit": "Edit Email Template",
|
||||
"label.quota.enddate": "End Date",
|
||||
"label.quota.endquota": "End Quota",
|
||||
"label.quota.enforce": "Enforce Quota",
|
||||
@ -1552,6 +1555,9 @@
|
||||
"label.quota.tariff.edit": "Edit Tariff",
|
||||
"label.quota.tariff.effectivedate": "Effective Date",
|
||||
"label.quota.totalusage": "Total Usage",
|
||||
"label.quota.total":"Total",
|
||||
"label.quota.type.name":"Usage Type",
|
||||
"label.quota.type.unit":"Usage Unit",
|
||||
"label.quota.usage": "Quota Consumption",
|
||||
"label.quota.value": "Quota Value",
|
||||
"label.rados.monitor": "RADOS Monitor",
|
||||
@ -1904,6 +1910,7 @@
|
||||
"label.tagged": "Tagged",
|
||||
"label.tags": "Tags",
|
||||
"label.target.iqn": "Target IQN",
|
||||
"label.tariffactions": "Actions",
|
||||
"label.tariffvalue": "Tariff Value",
|
||||
"label.task.completed": "Task completed",
|
||||
"label.tcp": "TCP",
|
||||
|
||||
@ -283,7 +283,9 @@
|
||||
</div>
|
||||
|
||||
<div v-if="dataView">
|
||||
<slot v-if="$route.path.startsWith('/quotasummary')"></slot>
|
||||
<resource-view
|
||||
v-else
|
||||
:resource="resource"
|
||||
:loading="loading"
|
||||
:tabs="$route.meta.tabs" />
|
||||
@ -342,6 +344,7 @@ export default {
|
||||
parentToggleLoading: this.toggleLoading,
|
||||
parentStartLoading: this.startLoading,
|
||||
parentFinishLoading: this.finishLoading,
|
||||
parentChangeResource: this.changeResource,
|
||||
parentPollActionCompletion: this.pollActionCompletion
|
||||
}
|
||||
},
|
||||
@ -446,6 +449,7 @@ export default {
|
||||
if (this.$route && this.$route.params && this.$route.params.id) {
|
||||
this.resource = {}
|
||||
this.dataView = true
|
||||
this.$emit('change-resource', this.resource)
|
||||
} else {
|
||||
this.dataView = false
|
||||
}
|
||||
@ -597,6 +601,7 @@ export default {
|
||||
}
|
||||
if (this.items.length > 0) {
|
||||
this.resource = this.items[0]
|
||||
this.$emit('change-resource', this.resource)
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
|
||||
136
ui/src/views/plugins/quota/EditTariffValueWizard.vue
Normal file
136
ui/src/views/plugins/quota/EditTariffValueWizard.vue
Normal file
@ -0,0 +1,136 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
v-if="showAction"
|
||||
style="top: 20px;"
|
||||
centered
|
||||
:confirmLoading="loading"
|
||||
:title="$t('label.quota.configuration')"
|
||||
:closable="true"
|
||||
:visible="showAction"
|
||||
@ok="submitTariff"
|
||||
@cancel="onClose"
|
||||
>
|
||||
<a-form
|
||||
:form="form"
|
||||
layout="vertical"
|
||||
@submit="submitTariff">
|
||||
<a-form-item :label="$t('label.quota.value')">
|
||||
<a-input
|
||||
v-decorator="['value', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: `${$t('message.error.required.input')}`
|
||||
}]
|
||||
}]"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('label.quota.tariff.effectivedate')">
|
||||
<a-date-picker
|
||||
:disabledDate="disabledDate"
|
||||
style="width: 100%"
|
||||
v-decorator="['startdate', {
|
||||
rules: [{
|
||||
type: 'object',
|
||||
required: true,
|
||||
message: `${$t('message.error.date')}`
|
||||
}]
|
||||
}]"></a-date-picker>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'EditTariffValueWizard',
|
||||
props: {
|
||||
showAction: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
pattern: 'YYYY-MM-DD'
|
||||
}
|
||||
},
|
||||
inject: ['parentEditTariffAction', 'parentFetchData'],
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
mounted () {
|
||||
this.form.getFieldDecorator('value', {
|
||||
initialValue: this.resource.tariffValue
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onClose () {
|
||||
this.parentEditTariffAction(false)
|
||||
},
|
||||
submitTariff (e) {
|
||||
e.preventDefault()
|
||||
this.form.validateFields((error, values) => {
|
||||
if (error) return
|
||||
|
||||
const params = {}
|
||||
params.usageType = this.resource.usageType
|
||||
params.value = values.value
|
||||
params.startdate = values.startdate.format(this.pattern)
|
||||
|
||||
this.loading = true
|
||||
|
||||
api('quotaTariffUpdate', {}, 'POST', params).then(json => {
|
||||
const tariffResponse = json.quotatariffupdateresponse.quotatariff || {}
|
||||
if (Object.keys(tariffResponse).length > 0) {
|
||||
const effectiveDate = moment(tariffResponse.effectiveDate).format(this.pattern)
|
||||
const query = this.$route.query
|
||||
if (query.startdate !== effectiveDate) {
|
||||
this.$router.replace({ path: 'quotatariff', query: { startdate: effectiveDate } })
|
||||
}
|
||||
this.parentFetchData()
|
||||
}
|
||||
|
||||
this.onClose()
|
||||
}).catch(error => {
|
||||
this.$notification.error({
|
||||
message: 'Request Failed',
|
||||
description: (error.response && error.response.headers && error.response.headers['x-description']) || error.message
|
||||
})
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
disabledDate (current) {
|
||||
return current && current < moment().endOf('day')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
121
ui/src/views/plugins/quota/EmailTemplateDetails.vue
Normal file
121
ui/src/views/plugins/quota/EmailTemplateDetails.vue
Normal file
@ -0,0 +1,121 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<a-spin :spinning="loading || loading">
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="24">
|
||||
<a-form-item :label="$t('label.templatesubject')">
|
||||
<a-textarea v-model="formModel.templatesubject" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="24">
|
||||
<a-form-item :label="$t('label.templatebody')">
|
||||
<a-textarea v-model="formModel.templatebody" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="24">
|
||||
<a-form-item :label="$t('label.last.updated')">
|
||||
<label>{{ resource.last_updated }}</label>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="24">
|
||||
<a-button
|
||||
style="float: right; margin-left: 10px;"
|
||||
:disabled="!('quotaEmailTemplateUpdate' in $store.getters.apis)"
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
@click="handleSubmit">{{ $t('label.apply') }}</a-button>
|
||||
<a-button
|
||||
style="float: right;"
|
||||
:disabled="!('quotaEmailTemplateUpdate' in $store.getters.apis)"
|
||||
:loading="loading"
|
||||
type="default"
|
||||
@click="() => { $router.go(-1) }">{{ $t('label.cancel') }}</a-button>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
|
||||
export default {
|
||||
name: 'EmailTemplateDetails',
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resource: {},
|
||||
formModel: {
|
||||
templatesubject: null,
|
||||
templatebody: null
|
||||
},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
this.loading = true
|
||||
const params = {}
|
||||
params.templatetype = this.$route.params.id
|
||||
|
||||
api('quotaEmailTemplateList', params).then(json => {
|
||||
const listTemplates = json.quotaemailtemplatelistresponse.quotaemailtemplate || []
|
||||
this.resource = listTemplates && listTemplates.length > 0 ? listTemplates[0] : {}
|
||||
this.preFillDataValues()
|
||||
}).catch(e => {
|
||||
this.$notifyError(e)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
preFillDataValues () {
|
||||
console.log(this.resource)
|
||||
this.formModel.templatesubject = this.resource.templatesubject || null
|
||||
this.formModel.templatebody = this.resource.templatebody || null
|
||||
},
|
||||
handleSubmit () {
|
||||
const params = {}
|
||||
params.templatesubject = this.formModel.templatesubject
|
||||
params.templatebody = this.formModel.templatebody
|
||||
params.templatetype = this.resource.templatetype
|
||||
|
||||
this.loading = true
|
||||
|
||||
api('quotaEmailTemplateUpdate', params).then(json => {
|
||||
this.$message.success(this.$t('label.quota.email.edit') + ' - ' + this.resource.templatetype)
|
||||
this.$router.go(-1)
|
||||
}).catch(e => {
|
||||
this.$notifyError(e)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
172
ui/src/views/plugins/quota/QuotaBalance.vue
Normal file
172
ui/src/views/plugins/quota/QuotaBalance.vue
Normal file
@ -0,0 +1,172 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-table
|
||||
size="small"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="record => record.name"
|
||||
:pagination="false"
|
||||
:scroll="{ y: '55vh' }"
|
||||
>
|
||||
<template slot="quota" slot-scope="text">
|
||||
<span v-if="text!==null">{{ `${currency} ${text}` }}</span>
|
||||
</template>
|
||||
<template slot="credit" slot-scope="text">
|
||||
<span v-if="text!==null">{{ `${currency} ${text}` }}</span>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'QuotaBalance',
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
tab: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
pattern: 'YYYY-MM-DD',
|
||||
currency: '',
|
||||
dataSource: [],
|
||||
account: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns () {
|
||||
return [
|
||||
{
|
||||
title: this.$t('label.date'),
|
||||
dataIndex: 'date',
|
||||
width: 'calc(100% / 3)',
|
||||
scopedSlots: { customRender: 'date' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.quota.value'),
|
||||
dataIndex: 'quota',
|
||||
width: 'calc(100% / 3)',
|
||||
scopedSlots: { customRender: 'quota' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.credit'),
|
||||
dataIndex: 'credit',
|
||||
width: 'calc(100% / 3)',
|
||||
scopedSlots: { customRender: 'credit' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tab (newTab, oldTab) {
|
||||
this.tab = newTab
|
||||
if (this.tab === 'quota.statement.balance') {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
async fetchData () {
|
||||
this.dataSource = []
|
||||
this.loading = true
|
||||
this.account = this.$route.query && this.$route.query.account ? this.$route.query.account : null
|
||||
|
||||
try {
|
||||
const resource = await this.fetchResource()
|
||||
const quotaBalance = await this.quotaBalance(resource)
|
||||
this.currency = quotaBalance.currency
|
||||
this.dataSource = await this.createDataSource(quotaBalance)
|
||||
this.loading = false
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
createDataSource (quotaBalance) {
|
||||
const dataSource = []
|
||||
const credits = quotaBalance.credits || []
|
||||
|
||||
dataSource.push({
|
||||
date: moment(quotaBalance.enddate).format(this.pattern),
|
||||
quota: quotaBalance.endquota,
|
||||
credit: null
|
||||
})
|
||||
dataSource.push({
|
||||
date: moment(quotaBalance.startdate).format(this.pattern),
|
||||
quota: quotaBalance.startquota,
|
||||
credit: null
|
||||
})
|
||||
credits.map(item => {
|
||||
dataSource.push({
|
||||
date: moment(item.updated_on).format(this.pattern),
|
||||
quota: null,
|
||||
credit: item.credits
|
||||
})
|
||||
})
|
||||
|
||||
return dataSource
|
||||
},
|
||||
fetchResource () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {}
|
||||
params.domainid = this.resource.domainid
|
||||
params.account = this.account
|
||||
|
||||
api('quotaBalance', params).then(json => {
|
||||
const quotaBalance = json.quotabalanceresponse.balance || {}
|
||||
resolve(quotaBalance)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
quotaBalance (resource) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {}
|
||||
params.domainid = this.resource.domainid
|
||||
params.account = this.account
|
||||
params.startdate = moment(this.resource.startdate).format(this.pattern)
|
||||
params.enddate = moment(resource.startdate).format(this.pattern)
|
||||
|
||||
api('quotaBalance', params).then(json => {
|
||||
const quotaBalance = json.quotabalanceresponse.balance || {}
|
||||
resolve(quotaBalance)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
66
ui/src/views/plugins/quota/QuotaSummary.vue
Normal file
66
ui/src/views/plugins/quota/QuotaSummary.vue
Normal file
@ -0,0 +1,66 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<autogen-view
|
||||
@change-resource="changeResource"/>
|
||||
<quota-summary-resource
|
||||
v-if="isSummaryResouce"
|
||||
:resource="resource"
|
||||
:tabs="$route.meta.tabs"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AutogenView from '@/views/AutogenView.vue'
|
||||
import QuotaSummaryResource from '@/views/plugins/quota/QuotaSummaryResource'
|
||||
|
||||
export default {
|
||||
name: 'QuotaSummary',
|
||||
components: {
|
||||
AutogenView,
|
||||
QuotaSummaryResource
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resource: {}
|
||||
}
|
||||
},
|
||||
provide: function () {
|
||||
return {
|
||||
parentChangeResource: this.changeResource
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSummaryResouce () {
|
||||
if (this.$route.path.startsWith('/quotasummary')) {
|
||||
if (this.$route.query && 'quota' in this.$route.query && this.$route.query.quota) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeResource (resource) {
|
||||
console.log(resource)
|
||||
this.resource = resource
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
92
ui/src/views/plugins/quota/QuotaSummaryResource.vue
Normal file
92
ui/src/views/plugins/quota/QuotaSummaryResource.vue
Normal file
@ -0,0 +1,92 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<resource-view
|
||||
:loading="loading"
|
||||
:resource="quotaResource"
|
||||
:tabs="tabs"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import moment from 'moment'
|
||||
|
||||
import ResourceView from '@/components/view/ResourceView'
|
||||
|
||||
export default {
|
||||
name: 'QuotaSummaryResource',
|
||||
components: {
|
||||
ResourceView
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
tabs: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
quotaResource: {},
|
||||
networkService: null,
|
||||
pattern: 'YYYY-MM-DD'
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
if (Object.keys(this.resource).length === 0) {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
inject: ['parentChangeResource'],
|
||||
methods: {
|
||||
fetchData () {
|
||||
const params = {}
|
||||
if (Object.keys(this.$route.query).length > 0) {
|
||||
Object.assign(params, this.$route.query)
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
api('quotaBalance', params).then(json => {
|
||||
const quotaBalance = json.quotabalanceresponse.balance || {}
|
||||
if (Object.keys(quotaBalance).length > 0) {
|
||||
quotaBalance.currency = `${quotaBalance.currency} ${quotaBalance.startquota}`
|
||||
quotaBalance.startdate = moment(quotaBalance.startdate).format(this.pattern)
|
||||
quotaBalance.account = this.$route.params.id ? this.$route.params.id : null
|
||||
quotaBalance.domainid = this.$route.query.domainid ? this.$route.query.domainid : null
|
||||
}
|
||||
this.quotaResource = Object.assign({}, this.quotaResource, quotaBalance)
|
||||
this.parentChangeResource(this.quotaResource)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
60
ui/src/views/plugins/quota/QuotaTariff.vue
Normal file
60
ui/src/views/plugins/quota/QuotaTariff.vue
Normal file
@ -0,0 +1,60 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<autogen-view ref="autogenview" />
|
||||
<edit-tariff-value-wizard
|
||||
v-if="tariffAction"
|
||||
:showAction="tariffAction"
|
||||
:resource="tariffResource" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AutogenView from '@/views/AutogenView.vue'
|
||||
import EditTariffValueWizard from '@/views/plugins/quota/EditTariffValueWizard'
|
||||
|
||||
export default {
|
||||
name: 'QuotaTariff',
|
||||
components: {
|
||||
AutogenView,
|
||||
EditTariffValueWizard
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tariffAction: false,
|
||||
tariffResource: {}
|
||||
}
|
||||
},
|
||||
provide: function () {
|
||||
return {
|
||||
parentFetchData: this.fetchData,
|
||||
parentEditTariffAction: this.showTariffAction
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
this.$refs.autogenview.fetchData()
|
||||
},
|
||||
showTariffAction (showAction, resource) {
|
||||
this.tariffAction = showAction
|
||||
this.tariffResource = resource
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
157
ui/src/views/plugins/quota/QuotaUsage.vue
Normal file
157
ui/src/views/plugins/quota/QuotaUsage.vue
Normal file
@ -0,0 +1,157 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-table
|
||||
size="small"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:rowKey="record => record.name"
|
||||
:pagination="false"
|
||||
:scroll="{ y: '55vh' }"
|
||||
>
|
||||
<template slot="quota" slot-scope="text">
|
||||
<span v-if="text!==undefined">{{ `${currency} ${text}` }}</span>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'QuotaUsage',
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
tab: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
dataSource: [],
|
||||
pattern: 'YYYY-MM-DD',
|
||||
currency: '',
|
||||
totalQuota: 0,
|
||||
account: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns () {
|
||||
return [
|
||||
{
|
||||
title: this.$t('label.quota.type.name'),
|
||||
dataIndex: 'name',
|
||||
width: 'calc(100% / 3)',
|
||||
scopedSlots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.quota.type.unit'),
|
||||
dataIndex: 'unit',
|
||||
width: 'calc(100% / 3)',
|
||||
scopedSlots: { customRender: 'unit' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.quota.usage'),
|
||||
dataIndex: 'quota',
|
||||
width: 'calc(100% / 3)',
|
||||
scopedSlots: { customRender: 'quota' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tab (newTab, oldTab) {
|
||||
this.tab = newTab
|
||||
if (this.tab === 'quota.statement.quota') {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
async fetchData () {
|
||||
this.loading = true
|
||||
this.dataSource = []
|
||||
this.account = this.$route.query && this.$route.query.account ? this.$route.query.account : null
|
||||
|
||||
try {
|
||||
const resource = await this.quotaBalance()
|
||||
const quotaStatement = await this.quotaStatement(resource)
|
||||
const quotaUsage = quotaStatement.quotausage
|
||||
this.dataSource = this.dataSource.concat(quotaUsage)
|
||||
this.currency = quotaStatement.currency
|
||||
this.totalQuota = quotaStatement.totalquota
|
||||
this.dataSource.push({
|
||||
name: `${this.$t('label.quota.total')}: `,
|
||||
quota: this.totalQuota
|
||||
})
|
||||
this.dataSource.unshift({
|
||||
type: 0,
|
||||
name: `${this.$t('startdate')}: ${moment(this.resource.startdate).format(this.pattern)}`,
|
||||
unit: `${this.$t('enddate')}: ${moment(this.resource.enddate).format(this.pattern)}`
|
||||
})
|
||||
this.loading = false
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
quotaBalance () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {}
|
||||
params.domainid = this.resource.domainid
|
||||
params.account = this.account
|
||||
|
||||
api('quotaBalance', params).then(json => {
|
||||
const quotaBalance = json.quotabalanceresponse.balance || {}
|
||||
resolve(quotaBalance)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
quotaStatement (resource) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {}
|
||||
params.domainid = this.resource.domainid
|
||||
params.account = this.account
|
||||
params.startdate = moment(this.resource.startdate).format(this.pattern)
|
||||
params.enddate = moment(resource.startdate).format(this.pattern)
|
||||
|
||||
api('quotaStatement', params).then(json => {
|
||||
const quotaStatement = json.quotastatementresponse.statement || {}
|
||||
resolve(quotaStatement)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Loading…
x
Reference in New Issue
Block a user