Skip to content

Commit c6839a8

Browse files
RitchieVincentrohityadavcloud
authored andcommitted
setting: reusable component (#63)
Implements reusable settings component and the list view for global settings tab. Signed-off-by: Rohit Yadav <[email protected]>
1 parent c9a75e2 commit c6839a8

File tree

11 files changed

+316
-20
lines changed

11 files changed

+316
-20
lines changed

ui/docs/api/apis.remaining

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ createPhysicalNetwork
2323
createPortableIpRange
2424
createPortForwardingRule
2525
createPrivateGateway
26-
createRolePermission
2726
createSecondaryStagingStore
2827
createSnapshotFromVMSnapshot
2928
createStaticRoute
@@ -50,15 +49,13 @@ deletePortableIpRange
5049
deletePortForwardingRule
5150
deletePrivateGateway
5251
deleteProjectInvitation
53-
deleteRolePermission
5452
deleteSecondaryStagingStore
5553
deleteSnapshotPolicies
5654
deleteSslCert
5755
deleteStaticRoute
5856
deleteStorageNetworkIpRange
5957
deleteVlanIpRange
6058
deleteVpnConnection
61-
deleteVpnCustomerGateway
6259
deleteVpnGateway
6360
findHostsForMigration
6461
findStoragePoolsForMigration
@@ -74,8 +71,6 @@ listDedicatedHosts
7471
listDedicatedPods
7572
listDedicatedZones
7673
listDeploymentPlanners
77-
listDetailOptions
78-
listDomainChildren
7974
listEgressFirewallRules
8075
listFirewallRules
8176
listHostHAProviders
@@ -95,7 +90,6 @@ listNetworkACLs
9590
listNetworkServiceProviders
9691
listNics
9792
listOsCategories
98-
listPhysicalNetworks
9993
listPortableIpRanges
10094
listPortForwardingRules
10195
listPrivateGateways
@@ -104,7 +98,6 @@ listProjectInvitations
10498
listRegisteredServicePackages
10599
listRemoteAccessVpns
106100
listResourceLimits
107-
listRolePermissions
108101
listSamlAuthorization
109102
listSecondaryStagingStores
110103
listSnapshotPolicies
@@ -134,7 +127,6 @@ revokeSecurityGroupEgress
134127
revokeSecurityGroupIngress
135128
startInternalLoadBalancerVM
136129
stopInternalLoadBalancerVM
137-
updateConfiguration
138130
updateDefaultNicForVirtualMachine
139131
updateLoadBalancerRule
140132
updateNetworkACLItem
@@ -143,9 +135,7 @@ updateNetworkServiceProvider
143135
updatePhysicalNetwork
144136
updateProjectInvitation
145137
updateResourceLimit
146-
updateRolePermission
147138
updateTrafficType
148139
updateVmNicIp
149140
updateVpnCustomerGateway
150-
uploadCustomCertificate
151141
uploadSslCert

ui/src/components/view/DetailSettings.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,18 @@
5050
:dataSource="detailOptions[item.name]"
5151
@change="val => handleInputChange(val, index)"
5252
@pressEnter="e => updateDetail(index)" />
53-
<a-button shape="circle" size="small" @click="updateDetail(index)" style="margin: 2px">
54-
<a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" style="font-size: 24px"/>
55-
</a-button>
56-
<a-button shape="circle" size="small" @click="hideEditDetail(index)" style="margin: 2px">
57-
<a-icon type="close-circle" theme="twoTone" twoToneColor="#f5222d" style="font-size: 24px"/>
58-
</a-button>
5953
</span>
6054
<span v-else>{{ item.value }}</span>
6155
</span>
6256
</a-list-item-meta>
6357
<div slot="actions">
64-
<a-button shape="circle" @click="showEditDetail(index)">
58+
<a-button shape="circle" size="default" @click="updateDetail(index)" v-if="item.edit">
59+
<a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
60+
</a-button>
61+
<a-button shape="circle" size="default" @click="hideEditDetail(index)" v-if="item.edit">
62+
<a-icon type="close-circle" theme="twoTone" twoToneColor="#f5222d" />
63+
</a-button>
64+
<a-button shape="circle" @click="showEditDetail(index)" v-if="!item.edit">
6565
<a-icon type="edit" />
6666
</a-button>
6767
</div>

ui/src/components/view/ListView.vue

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
:columns="columns"
2323
:dataSource="items"
2424
:rowKey="record => record.id || record.name"
25-
:scroll="{ x: '100%' }"
2625
:pagination="false"
2726
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
2827
:rowClassName="getRowClassName"
@@ -101,10 +100,44 @@
101100
<a slot="zonename" slot-scope="text, record" href="javascript:;">
102101
<router-link :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
103102
</a>
103+
104+
<template slot="value" slot-scope="text, record">
105+
<a-input
106+
v-if="editableValueKey === record.key"
107+
:defaultValue="record.value"
108+
v-model="editableValue"
109+
@keydown.esc="editableValueKey = null"
110+
@pressEnter="saveValue(record)">
111+
</a-input>
112+
<div v-else style="width: 200px; word-break: break-all">
113+
{{ text }}
114+
</div>
115+
</template>
116+
<template slot="actions" slot-scope="text, record">
117+
<a-button
118+
shape="circle"
119+
v-if="editableValueKey !== record.key"
120+
icon="edit"
121+
@click="editValue(record)" />
122+
<a-button
123+
shape="circle"
124+
@click="saveValue(record)"
125+
v-if="editableValueKey === record.key" >
126+
<a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
127+
</a-button>
128+
<a-button
129+
shape="circle"
130+
size="default"
131+
@click="editableValueKey = null"
132+
v-if="editableValueKey === record.key" >
133+
<a-icon type="close-circle" theme="twoTone" twoToneColor="#f5222d" />
134+
</a-button>
135+
</template>
104136
</a-table>
105137
</template>
106138

107139
<script>
140+
import { api } from '@/api'
108141
import Console from '@/components/widgets/Console'
109142
import Status from '@/components/widgets/Status'
110143
@@ -130,7 +163,9 @@ export default {
130163
},
131164
data () {
132165
return {
133-
selectedRowKeys: []
166+
selectedRowKeys: [],
167+
editableValueKey: null,
168+
editableValue: ''
134169
}
135170
},
136171
computed: {
@@ -154,6 +189,30 @@ export default {
154189
this.$store.dispatch('ToggleTheme', project.id === undefined ? 'light' : 'dark')
155190
this.$message.success(`Switched to "${project.name}"`)
156191
this.$router.push({ name: 'dashboard' })
192+
},
193+
saveValue (record) {
194+
api('updateConfiguration', {
195+
name: record.name,
196+
value: this.editableValue
197+
}).then(() => {
198+
this.editableValueKey = null
199+
200+
this.$message.success('Setting Updated: ' + record.name)
201+
this.$notification.warning({
202+
message: 'Status',
203+
description: 'Please restart your management server(s) for your new settings to take effect.'
204+
})
205+
}).catch(error => {
206+
console.error(error)
207+
this.$message.error('There was an error saving this setting.')
208+
})
209+
.finally(() => {
210+
this.$emit('refresh')
211+
})
212+
},
213+
editValue (record) {
214+
this.editableValueKey = record.key
215+
this.editableValue = record.value
157216
}
158217
}
159218
}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
<template>
2+
<a-list size="large" class="list" :loading="loading">
3+
<a-list-item :key="index" v-for="(item, index) in items" class="item">
4+
<a-list-item-meta>
5+
<span slot="title" style="word-break: break-all"><strong>{{ item.name }}</strong></span>
6+
<span slot="description" style="word-break: break-all">{{ item.description }}</span>
7+
</a-list-item-meta>
8+
9+
<div class="item__content">
10+
<a-input
11+
v-if="editableValueKey === index"
12+
class="editable-value value"
13+
:defaultValue="item.value"
14+
v-model="editableValue"
15+
@keydown.esc="editableValueKey = null"
16+
@pressEnter="updateData(item)">
17+
</a-input>
18+
<span v-else class="value">
19+
{{ item.value }}
20+
</span>
21+
</div>
22+
23+
<div slot="actions" class="action">
24+
<a-button
25+
shape="circle"
26+
v-if="editableValueKey !== index"
27+
icon="edit"
28+
@click="setEditableSetting(item, index)" />
29+
<a-button
30+
shape="circle"
31+
size="default"
32+
@click="editableValueKey = null"
33+
v-if="editableValueKey === index" >
34+
<a-icon type="close-circle" theme="twoTone" twoToneColor="#f5222d" />
35+
</a-button>
36+
<a-button
37+
shape="circle"
38+
@click="updateData(item)"
39+
v-if="editableValueKey === index" >
40+
<a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
41+
</a-button>
42+
</div>
43+
</a-list-item>
44+
</a-list>
45+
</template>
46+
47+
<script>
48+
import { api } from '@/api'
49+
50+
export default {
51+
name: 'SettingsTab',
52+
props: {
53+
resource: {
54+
type: Object,
55+
required: true
56+
},
57+
loading: {
58+
type: Boolean,
59+
required: true
60+
}
61+
},
62+
data () {
63+
return {
64+
items: [],
65+
scopeKey: '',
66+
editableValueKey: null,
67+
editableValue: ''
68+
}
69+
},
70+
beforeMount () {
71+
switch (this.$route.meta.name) {
72+
case 'account':
73+
this.scopeKey = 'accountid'
74+
break
75+
case 'domain':
76+
this.scopeKey = 'domainid'
77+
break
78+
case 'zone':
79+
this.scopeKey = 'zoneid'
80+
break
81+
case 'cluster':
82+
this.scopeKey = 'clusterid'
83+
break
84+
case 'storagepool':
85+
this.scopeKey = 'storageid'
86+
break
87+
case 'imagestore':
88+
this.scopeKey = 'imagestoreuuid'
89+
break
90+
default:
91+
this.scopeKey = ''
92+
}
93+
},
94+
mounted () {
95+
this.fetchData()
96+
},
97+
watch: {
98+
resource: newItem => {
99+
if (!newItem.id) return
100+
this.fetchData()
101+
}
102+
},
103+
methods: {
104+
fetchData (callback) {
105+
this.loading = true
106+
api('listConfigurations', {
107+
[this.scopeKey]: this.resource.id,
108+
listAll: true
109+
}).then(response => {
110+
this.items = response.listconfigurationsresponse.configuration
111+
}).catch(error => {
112+
console.error(error)
113+
this.$message.error('There was an error loading these settings.')
114+
}).finally(() => {
115+
this.loading = false
116+
if (!callback) return
117+
callback()
118+
})
119+
},
120+
updateData (item) {
121+
this.loading = true
122+
api('updateConfiguration', {
123+
[this.scopeKey]: this.resource.id,
124+
name: item.name,
125+
value: this.editableValue
126+
}).then(() => {
127+
this.$message.success('Setting ' + item.name + ' updated to ' + this.editableValue)
128+
}).catch(error => {
129+
console.error(error)
130+
this.$message.error('There was an error saving this setting.')
131+
this.$notification.error({
132+
message: 'Error',
133+
description: 'There was an error saving this setting. Please try again later.'
134+
})
135+
}).finally(() => {
136+
this.loading = false
137+
this.fetchData(() => {
138+
this.editableValueKey = null
139+
})
140+
})
141+
},
142+
setEditableSetting (item, index) {
143+
this.editableValueKey = index
144+
this.editableValue = item.value
145+
}
146+
}
147+
}
148+
</script>
149+
150+
<style scoped lang="scss">
151+
.list {
152+
}
153+
.editable-value {
154+
155+
@media (min-width: 760px) {
156+
text-align: right;
157+
margin-left: 40px;
158+
margin-right: -40px;
159+
}
160+
161+
}
162+
.item {
163+
display: flex;
164+
flex-direction: column;
165+
align-items: stretch;
166+
167+
@media (min-width: 760px) {
168+
flex-direction: row;
169+
}
170+
171+
&__content {
172+
width: 100%;
173+
display: flex;
174+
word-break: break-all;
175+
176+
@media (min-width: 760px) {
177+
width: auto;
178+
}
179+
180+
}
181+
182+
}
183+
.action {
184+
margin-top: 20px;
185+
margin-left: -12px;
186+
187+
@media (min-width: 480px) {
188+
margin-left: -24px;
189+
}
190+
191+
@media (min-width: 760px) {
192+
margin-top: 0;
193+
margin-left: 0;
194+
}
195+
196+
}
197+
198+
.value {
199+
margin-top: 20px;
200+
201+
@media (min-width: 760px) {
202+
margin-top: 0;
203+
}
204+
205+
}
206+
207+
</style>

0 commit comments

Comments
 (0)