iam: Account Cert Tab (#66)

Fixes #46

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Hoang Nguyen 2019-12-12 00:24:02 +07:00 committed by Rohit Yadav
parent c6839a8550
commit 21036bfba4
8 changed files with 303 additions and 21 deletions

View File

@ -51,7 +51,6 @@ deletePrivateGateway
deleteProjectInvitation
deleteSecondaryStagingStore
deleteSnapshotPolicies
deleteSslCert
deleteStaticRoute
deleteStorageNetworkIpRange
deleteVlanIpRange
@ -101,7 +100,6 @@ listResourceLimits
listSamlAuthorization
listSecondaryStagingStores
listSnapshotPolicies
listSslCerts
listStaticRoutes
listStorageNetworkIpRange
listStorageProviders
@ -138,4 +136,3 @@ updateResourceLimit
updateTrafficType
updateVmNicIp
updateVpnCustomerGateway
uploadSslCert

View File

@ -41,7 +41,7 @@
<a-list size="large">
<a-list-item :key="index" v-for="(item, index) in details">
<a-list-item-meta>
<span slot="title">{{ item.name }}</span>
<span slot="title"><strong>{{ item.name }}</strong></span>
<span slot="description" style="word-break: break-all">
<span v-if="item.edit" style="display: flex">
<a-auto-complete
@ -51,7 +51,7 @@
@change="val => handleInputChange(val, index)"
@pressEnter="e => updateDetail(index)" />
</span>
<span v-else>{{ item.value }}</span>
<span v-else @click="showEditDetail(index)">{{ item.value }}</span>
</span>
</a-list-item-meta>
<div slot="actions">

View File

@ -37,7 +37,7 @@
:tab="$t(tab.name)"
:key="tab.name"
v-if="'show' in tab ? tab.show(resource, $route) : true">
<component :is="tab.component" :resource="resource" :loading="loading" />
<component :is="tab.component" :resource="resource" :loading="loading" :tab="activeTab" />
</a-tab-pane>
</a-tabs>
</a-card>
@ -76,6 +76,11 @@ export default {
}
}
},
data () {
return {
activeTab: ''
}
},
methods: {
onTabChange (key) {
this.activeTab = key

View File

@ -1,5 +1,5 @@
<template>
<a-list size="large" class="list" :loading="loading">
<a-list size="large" class="list" :loading="loading || tabLoading">
<a-list-item :key="index" v-for="(item, index) in items" class="item">
<a-list-item-meta>
<span slot="title" style="word-break: break-all"><strong>{{ item.name }}</strong></span>
@ -15,7 +15,7 @@
@keydown.esc="editableValueKey = null"
@pressEnter="updateData(item)">
</a-input>
<span v-else class="value">
<span v-else class="value" @click="setEditableSetting(item, index)">
{{ item.value }}
</span>
</div>
@ -64,7 +64,8 @@ export default {
items: [],
scopeKey: '',
editableValueKey: null,
editableValue: ''
editableValue: '',
tabLoading: false
}
},
beforeMount () {
@ -95,14 +96,15 @@ export default {
this.fetchData()
},
watch: {
resource: newItem => {
resource: function (newItem, oldItem) {
if (!newItem.id) return
this.resource = newItem
this.fetchData()
}
},
methods: {
fetchData (callback) {
this.loading = true
this.tabLoading = true
api('listConfigurations', {
[this.scopeKey]: this.resource.id,
listAll: true
@ -112,13 +114,13 @@ export default {
console.error(error)
this.$message.error('There was an error loading these settings.')
}).finally(() => {
this.loading = false
this.tabLoading = false
if (!callback) return
callback()
})
},
updateData (item) {
this.loading = true
this.tabLoading = true
api('updateConfiguration', {
[this.scopeKey]: this.resource.id,
name: item.name,
@ -133,7 +135,7 @@ export default {
description: 'There was an error saving this setting. Please try again later.'
})
}).finally(() => {
this.loading = false
this.tabLoading = false
this.fetchData(() => {
this.editableValueKey = null
})

View File

@ -90,13 +90,20 @@ export default {
title: 'Users',
param: 'account'
}],
tabs: [{
name: 'details',
component: () => import('@/components/view/DetailsTab.vue')
}, {
name: 'Settings',
component: () => import('@/components/view/SettingsTab.vue')
}],
tabs: [
{
name: 'details',
component: () => import('@/components/view/DetailsTab.vue')
},
{
name: 'certificate',
component: () => import('@/views/iam/SSLCertificateTab.vue')
},
{
name: 'Settings',
component: () => import('@/components/view/SettingsTab.vue')
}
],
actions: [
{
api: 'createAccount',
@ -161,6 +168,14 @@ export default {
}
}
},
{
api: 'uploadSslCert',
icon: 'safety-certificate',
label: 'Add certificate',
dataView: true,
args: ['name', 'certificate', 'privatekey', 'certchain', 'password'],
show: (record) => { return record.state === 'enabled' }
},
{
api: 'deleteAccount',
icon: 'delete',

View File

@ -99,6 +99,7 @@
"capacityiops": "IOPS Total",
"certchain": "Chain",
"certificate": "Certificate",
"certificateid": "Certificate ID",
"chassis": "Chassis",
"checksum": "checksum",
"cidr": "Super CIDR for Guest Networks",
@ -133,6 +134,7 @@
"current": "isCurrent",
"date": "Date",
"dedicated": "Dedicated",
"deleteconfirm": "Please confirm that you would like to delete this {name}",
"deleteprofile": "Delete Profile",
"deploymentPlanner": "Deployment planner",
"deploymentplanner": "Deployment planner",
@ -435,6 +437,7 @@
"label.add.isolated.network": "Add Isolated Network",
"label.add.l2.guest.network": "Add L2 Guest Network",
"label.add.ldap.account": "Add LDAP account",
"label.add.ldap.list.users": "List LDAP users",
"label.add.netScaler.device": "Add Netscaler device",
"label.add.network.offering": "Add network offering",
"label.add.new.tier": "Add new tier",
@ -734,6 +737,7 @@
"publicport": "Public Port",
"purpose": "Purpose",
"qosType": "QoS Type",
"quickview": "Quick view",
"quiescevm": "Quiesce VM",
"quietTime": "Quiet Time (in sec)",
"quota": "Quota Value",

View File

@ -177,6 +177,15 @@
:placeholder="field.description"
/>
</span>
<span v-else-if="field.name==='certificate' || field.name==='privatekey' || field.name==='certchain'">
<a-textarea
rows="2"
v-decorator="[field.name, {
rules: [{ required: field.required, message: 'Please enter input' }]
}]"
:placeholder="field.description"
/>
</span>
<span v-else>
<a-input
v-decorator="[field.name, {

View File

@ -0,0 +1,250 @@
// 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-row :gutter="12">
<a-col :md="24" :lg="24">
<a-table
size="small"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:rowKey="record => record.id"
:pagination="false"
v-if="!quickview"
>
<span slot="action" slot-scope="text, record" class="cert-button-action">
<a-tooltip placement="top">
<template slot="title">
{{ $t('quickview') }}
</template>
<a-button type="primary" shape="circle" icon="eye" size="small" @click="onQuickView(record.id)" />
</a-tooltip>
<a-tooltip placement="top">
<template slot="title">
{{ $t('Delete SSL Certificate') }}
</template>
<a-button
type="danger"
shape="circle"
icon="delete"
size="small"
@click="onShowConfirm(record)"/>
</a-tooltip>
</span>
</a-table>
<a-list size="small" :dataSource="detailColumn" v-if="quickview">
<div class="close-quickview">
<a-button @click="() => { this.quickview = false }">{{ $t('close') }}</a-button>
</div>
<a-list-item slot="renderItem" slot-scope="item" v-if="item in detail">
<div>
<strong>{{ $t(item) }}</strong>
<br/>
<div class="list-item-content">
{{ detail[item] }}
</div>
</div>
</a-list-item>
</a-list>
</a-col>
</a-row>
</div>
</template>
<script>
import { api } from '@/api'
export default {
name: 'SSLCertificate',
data () {
return {
columns: [],
dataSource: [],
selectedRowKeys: [],
detailColumn: [],
detail: [],
page: 1,
pageSize: 20,
quickview: false,
loading: false
}
},
props: {
resource: {
type: Object,
default () {
return {}
}
},
tab: {
type: String,
default () {
return ''
}
}
},
watch: {
tab (newValue, oldValue) {
if (newValue === 'certificate') {
this.quickview = false
this.fetchData()
}
},
resource (newValue, oldValue) {
if (Object.keys(newValue).length > 0 &&
newValue.id &&
this.tab === 'certificate'
) {
this.quickview = false
this.fetchData()
}
}
},
created () {
this.columns = [
{
title: this.$t('name'),
dataIndex: 'name',
scopedSlots: { customRender: 'name' }
},
{
title: this.$t('certificateid'),
dataIndex: 'id',
width: 450,
scopedSlots: { customRender: 'id' }
},
{
title: this.$t('action'),
dataIndex: 'action',
fixed: 'right',
width: 80,
scopedSlots: { customRender: 'action' }
}
]
this.detailColumn = ['name', 'certificate', 'certchain']
},
mounted () {
this.fetchData()
},
methods: {
fetchData () {
const params = {}
params.listAll = true
params.page = this.page
params.pageSize = this.pageSize
params.accountid = this.resource.id
this.loading = true
api('listSslCerts', params).then(json => {
const listSslResponse = json.listsslcertsresponse.sslcert
// check exists json response
if (!listSslResponse || Object.keys(listSslResponse).length === 0) {
this.dataSource = []
return
}
this.dataSource = listSslResponse
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.loading = false
})
},
onQuickView (id) {
this.loading = true
const detail = this.dataSource.filter(item => item.id === id)
this.detail = detail[0]
this.quickview = true
this.loading = false
},
onDelete (row) {
const params = {}
params.id = row.id
// show loading
const loading = this.$message.loading('Delete certificate in progress for ' + row.name, 0)
api('deleteSslCert', params).then(json => {
const jsonResponse = json.deletesslcertresponse
// hide loading
setTimeout(loading)
if (jsonResponse.success) {
this.$message.success('Delete success', 3)
this.fetchData()
} else {
this.$message.error('Delete fail', 3)
}
}).catch(error => {
// hide loading
setTimeout(loading)
// show error
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
})
},
onShowConfirm (row) {
const self = this
let title = this.$t('deleteconfirm')
title = title.replace('{name}', this.$t('certificate'))
this.$confirm({
title: title,
okText: 'OK',
okType: 'danger',
cancelText: 'Cancel',
onOk () {
self.onDelete(row)
}
})
}
}
}
</script>
<style scoped>
/deep/.ant-table-fixed-right {
z-index: 5;
}
.cert-button-action button {
margin-right: 5px;
}
.list-item-content {
word-break: break-word;
}
.close-quickview {
text-align: right;
margin-top: 12px;
line-height: 32px;
height: 32px;
}
</style>