mirror of
https://github.com/veops/cmdb.git
synced 2025-08-25 18:12:20 +08:00
feat(ui): add automatic subscription #285
This commit is contained in:
@@ -157,3 +157,18 @@ export function preferenceCitypeOrder(data) {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getAutoSubscription() {
|
||||
return axios({
|
||||
url: '/v0.1/preference/auto_subscription',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
export function putAutoSubscription(data) {
|
||||
return axios({
|
||||
url: '/v0.1/preference/auto_subscription',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
@@ -222,12 +222,14 @@ const cmdb_en = {
|
||||
otherGroupTips: 'Non sortable within the other group',
|
||||
filterTips: 'click to show {name}',
|
||||
attributeAssociation: 'Attribute Association',
|
||||
attributeAssociationTip1: 'Automatically establish relationships through attribute values (except password, json, multi-value, long text, boolean, reference) of two models',
|
||||
attributeAssociationTip1: 'Automatically establish relationships through attribute values (except password, json, long text, boolean, reference) of two models',
|
||||
attributeAssociationTip2: 'Double click to edit',
|
||||
attributeAssociationTip3: 'Two Attributes must be selected',
|
||||
attributeAssociationTip4: 'Please select a attribute from Source CIType',
|
||||
attributeAssociationTip5: 'Please select a attribute from Target CIType',
|
||||
attributeAssociationTip6: 'Cannot be deleted again.',
|
||||
attributeAssociationTip7: '1. The attribute value types of the source model and target model must be consistent.',
|
||||
attributeAssociationTip8: '2. One To Many: Source model can select multiple value attributes',
|
||||
show: 'show attribute',
|
||||
setAsShow: 'Set as show attribute',
|
||||
cancelSetAsShow: 'Cancel show attribute',
|
||||
@@ -460,6 +462,20 @@ const cmdb_en = {
|
||||
searchPlaceholder: 'Please search CIType',
|
||||
subCITable: 'Data',
|
||||
subCITree: 'Tree',
|
||||
autoSub: 'Auto Subscription',
|
||||
autoSub2: 'Click To Enable Auto Subscribe',
|
||||
autoSubScope: 'Auto Subscription Scope',
|
||||
subscribeAllModel: 'Subscribe All Models',
|
||||
selectiveSubscription: 'Selective Subscription',
|
||||
excludeGroup: 'Exclude Group',
|
||||
excludeModel: 'Exclude Model',
|
||||
selectGroup: 'Select Group',
|
||||
selectModel: 'Select Model',
|
||||
isEnable: 'Is Enable',
|
||||
enableAutoSubTip: 'After enabling automatic subscription, the model list in the resource data menu will only be based on the results of automatic subscription.',
|
||||
tips1: 'Please go to',
|
||||
tips2: ' Preference ',
|
||||
tips3: 'page first to complete your subscription!'
|
||||
},
|
||||
custom_dashboard: {
|
||||
charts: 'Chart',
|
||||
@@ -748,7 +764,6 @@ if __name__ == "__main__":
|
||||
searchTips: 'Search in service tree'
|
||||
},
|
||||
tree: {
|
||||
tips1: 'Please go to Preference page first to complete your subscription!',
|
||||
subSettings: 'Settings',
|
||||
},
|
||||
topo: {
|
||||
|
@@ -222,12 +222,14 @@ const cmdb_zh = {
|
||||
otherGroupTips: '其他分组属性不可排序',
|
||||
filterTips: '点击可仅查看{name}属性',
|
||||
attributeAssociation: '属性关联',
|
||||
attributeAssociationTip1: '通过2个模型的属性值(除密码、json、多值、长文本、布尔、引用)来自动建立关系',
|
||||
attributeAssociationTip1: '通过2个模型的属性值(除密码、json、长文本、布尔、引用)来自动建立关系',
|
||||
attributeAssociationTip2: '双击可编辑',
|
||||
attributeAssociationTip3: '属性关联必须选择两个属性',
|
||||
attributeAssociationTip4: '请选择原模型属性',
|
||||
attributeAssociationTip5: '请选择目标模型属性',
|
||||
attributeAssociationTip6: '不可再删除',
|
||||
attributeAssociationTip7: '1. 源模型和目标模型的属性值类型必须保持一致',
|
||||
attributeAssociationTip8: '2. 一对多:源模型可选多值属性',
|
||||
show: '展示属性',
|
||||
setAsShow: '设置为展示属性',
|
||||
cancelSetAsShow: '取消设置为展示属性',
|
||||
@@ -459,6 +461,20 @@ const cmdb_zh = {
|
||||
searchPlaceholder: '请搜索模型',
|
||||
subCITable: '数据订阅',
|
||||
subCITree: '层级订阅',
|
||||
autoSub: '自动订阅',
|
||||
autoSub2: '点击开启自动订阅',
|
||||
autoSubScope: '自动订阅范围',
|
||||
subscribeAllModel: '订阅所有模型',
|
||||
selectiveSubscription: '选择性订阅',
|
||||
excludeGroup: '排除分组',
|
||||
excludeModel: '排除模型',
|
||||
selectGroup: '选择分组',
|
||||
selectModel: '选择模型',
|
||||
isEnable: '是否启用',
|
||||
enableAutoSubTip: '开启自动订阅后,资源数据菜单的模型列表只以自动订阅的结果为准',
|
||||
tips1: '请先到',
|
||||
tips2: ' 我的订阅 ',
|
||||
tips3: '页面完成订阅!',
|
||||
},
|
||||
custom_dashboard: {
|
||||
charts: '图表',
|
||||
@@ -747,7 +763,6 @@ if __name__ == "__main__":
|
||||
searchTips: '在服务树中筛选'
|
||||
},
|
||||
tree: {
|
||||
tips1: '请先到 我的订阅 页面完成订阅!',
|
||||
subSettings: '订阅设置',
|
||||
},
|
||||
topo: {
|
||||
|
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="$t('cmdb.preference.autoSub')"
|
||||
:visible="visible"
|
||||
:width="600"
|
||||
@cancel="handleCancel"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<a-form-model
|
||||
ref="autuSubFormRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="{ span: 7 }"
|
||||
:wrapper-col="{ span: 15 }"
|
||||
>
|
||||
<a-form-model-item
|
||||
:label="$t('cmdb.preference.autoSubScope')"
|
||||
prop="base_strategy"
|
||||
>
|
||||
<a-radio-group
|
||||
v-model="form.base_strategy"
|
||||
:options="baseStrategyOptions"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
:label="form.base_strategy === 'all' ? $t('cmdb.preference.excludeGroup') : $t('cmdb.preference.selectGroup')"
|
||||
prop="group_ids"
|
||||
>
|
||||
<a-select
|
||||
v-model="form.group_ids"
|
||||
mode="multiple"
|
||||
optionFilterProp="title"
|
||||
:options="groupSelectOptions"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
|
||||
<a-form-model-item
|
||||
:label="form.base_strategy === 'all' ? $t('cmdb.preference.excludeModel') : $t('cmdb.preference.selectModel')"
|
||||
prop="type_ids"
|
||||
>
|
||||
<a-select
|
||||
v-model="form.type_ids"
|
||||
mode="multiple"
|
||||
optionFilterProp="title"
|
||||
>
|
||||
<a-select-opt-group
|
||||
v-for="(group) in modelSelectOptions"
|
||||
:key="group.value"
|
||||
:title="group.label"
|
||||
>
|
||||
<span slot="label">{{ group.label }}</span>
|
||||
<a-select-option
|
||||
v-for="(type) in group.children"
|
||||
:key="type.value"
|
||||
:value="type.value"
|
||||
:title="type.label"
|
||||
>
|
||||
{{ type.label }}
|
||||
</a-select-option>
|
||||
</a-select-opt-group>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
|
||||
<a-form-model-item
|
||||
:label="$t('cmdb.preference.isEnable')"
|
||||
prop="enabled"
|
||||
:extra="$t('cmdb.preference.enableAutoSubTip')"
|
||||
>
|
||||
<a-switch v-model="form.enabled" />
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { putAutoSubscription } from '@/modules/cmdb/api/preference.js'
|
||||
|
||||
export default {
|
||||
name: 'AutoSubscribe',
|
||||
props: {
|
||||
ciType: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
autoSub: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
form: {
|
||||
base_strategy: 'all',
|
||||
group_ids: [],
|
||||
type_ids: [],
|
||||
enabled: true,
|
||||
},
|
||||
rules: {
|
||||
base_strategy: [{ required: true, message: this.$t('placeholder2') }],
|
||||
},
|
||||
baseStrategyOptions: [
|
||||
{
|
||||
label: this.$t('cmdb.preference.subscribeAllModel'),
|
||||
value: 'all'
|
||||
},
|
||||
{
|
||||
label: this.$t('cmdb.preference.selectiveSubscription'),
|
||||
value: 'none'
|
||||
}
|
||||
],
|
||||
groupSelectOptions: [],
|
||||
modelSelectOptions: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async open() {
|
||||
this.form = {
|
||||
base_strategy: this.autoSub?.base_strategy || 'all',
|
||||
group_ids: this.autoSub?.group_ids || [],
|
||||
type_ids: this.autoSub?.type_ids || [],
|
||||
enabled: this.autoSub?.enabled ?? true
|
||||
}
|
||||
|
||||
this.groupSelectOptions = this.ciType.map((group) => {
|
||||
return {
|
||||
label: group.name,
|
||||
title: group.name,
|
||||
value: group.id
|
||||
}
|
||||
})
|
||||
|
||||
const modelSelectOptions = this.ciType.filter((group) => group?.ci_types?.length)
|
||||
this.modelSelectOptions = modelSelectOptions.map((group) => {
|
||||
return {
|
||||
label: group.name,
|
||||
value: group.id,
|
||||
children: group.ci_types.map((type) => {
|
||||
return {
|
||||
label: type.alias || type.name,
|
||||
value: type.id
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.visible = true
|
||||
},
|
||||
handleCancel() {
|
||||
this.visible = false
|
||||
},
|
||||
handleOk() {
|
||||
this.$refs.autuSubFormRef.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const { base_strategy, group_ids, type_ids, enabled } = this.form
|
||||
|
||||
const params = {
|
||||
base_strategy: base_strategy,
|
||||
group_ids: group_ids.join(','),
|
||||
type_ids: type_ids.join(','),
|
||||
enabled: enabled
|
||||
}
|
||||
|
||||
putAutoSubscription(params).then(() => {
|
||||
this.$message.success(this.$t('saveSuccess'))
|
||||
this.handleCancel()
|
||||
this.$emit('ok')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
@@ -86,13 +86,15 @@
|
||||
</div>
|
||||
<span class="cmdb-preference-group-content-title">{{ ciType.alias || ciType.name }}</span>
|
||||
<span class="cmdb-preference-group-content-action">
|
||||
<a-tooltip :title="$t('cmdb.preference.cancelSub')">
|
||||
<span
|
||||
@click="unsubscribe(ciType, group.type)"
|
||||
><ops-icon type="cmdb-preference-cancel-subscribe" />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" :style="{ margin: '0 3px' }" />
|
||||
<template v-if="!enableAutoSub || subType.type === 'tree'">
|
||||
<a-tooltip :title="$t('cmdb.preference.cancelSub')">
|
||||
<span
|
||||
@click="unsubscribe(ciType, group.type)"
|
||||
><ops-icon type="cmdb-preference-cancel-subscribe" />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" :style="{ margin: '0 3px' }" />
|
||||
</template>
|
||||
<a-tooltip :title="$t('cmdb.preference.editSub')">
|
||||
<span
|
||||
@click="openSubscribeSetting(ciType, `${index + 1}`)"
|
||||
@@ -108,11 +110,23 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="cmdb-preference-right">
|
||||
<a-input-search
|
||||
v-model="searchValue"
|
||||
:style="{ width: '300px', marginBottom: '20px' }"
|
||||
:placeholder="$t('cmdb.preference.searchPlaceholder')"
|
||||
/>
|
||||
<div class="cmdb-preference-right-header">
|
||||
<a-input-search
|
||||
v-model="searchValue"
|
||||
class="cmdb-preference-right-header-search"
|
||||
:placeholder="$t('cmdb.preference.searchPlaceholder')"
|
||||
/>
|
||||
<div
|
||||
:class="[
|
||||
'cmdb-preference-right-header-auto',
|
||||
enableAutoSub ? 'cmdb-preference-right-header-auto_enable' : ''
|
||||
]"
|
||||
@click="openAutoSubModal"
|
||||
>
|
||||
<ops-icon type="auto" />
|
||||
<span>{{ enableAutoSub ? $t('cmdb.preference.autoSub') : $t('cmdb.preference.autoSub2') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="group in filterCiTypeData" :key="group.id">
|
||||
<p
|
||||
@click="changeGroupExpand(group)"
|
||||
@@ -154,14 +168,6 @@
|
||||
{{ item.alias || item.name }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="cmdb-preference-colleague">
|
||||
<span
|
||||
v-if="type_id2users[item.id] && type_id2users[item.id].length"
|
||||
>{{ type_id2users[item.id].length > 99 ? '99+' : type_id2users[item.id].length
|
||||
}}{{ $t('cmdb.preference.peopleSub') }}</span
|
||||
>
|
||||
<span v-else>{{ $t('cmdb.preference.noSub') }}</span>
|
||||
</div>
|
||||
<div class="cmdb-preference-progress">
|
||||
<div class="cmdb-preference-progress-info">
|
||||
<span>{{ $t('cmdb.menu.ad') }}</span>
|
||||
@@ -173,11 +179,20 @@
|
||||
</div>
|
||||
<a-divider :style="{ margin: '10px 0 3px 0' }" />
|
||||
<div class="cmdb-preference-footor-subscribed" v-if="item.is_subscribed">
|
||||
<span><a-icon type="clock-circle" :style="{ marginRight: '3px' }" />{{ getsubscribedDays(item) }}</span>
|
||||
<span
|
||||
:style="{
|
||||
opacity: enableAutoSub ? 0 : 1
|
||||
}"
|
||||
>
|
||||
<a-icon type="clock-circle" :style="{ marginRight: '3px' }" />{{ getsubscribedDays(item) }}
|
||||
</span>
|
||||
<span>
|
||||
<a-tooltip :title="$t('cmdb.preference.cancelSub')">
|
||||
<span @click="unsubscribe(item)"><ops-icon type="cmdb-preference-cancel-subscribe" /> </span>
|
||||
</a-tooltip>
|
||||
<template v-if="!enableAutoSub">
|
||||
<a-tooltip :title="$t('cmdb.preference.cancelSub')">
|
||||
<span @click="unsubscribe(item)"><ops-icon type="cmdb-preference-cancel-subscribe" /> </span>
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" :style="{ margin: '0 3px' }" />
|
||||
</template>
|
||||
<a-divider type="vertical" :style="{ margin: '0 3px' }" />
|
||||
<a-tooltip :title="$t('cmdb.preference.editSub')">
|
||||
<span @click="openSubscribeSetting(item)"><ops-icon type="cmdb-preference-subscribe"/></span>
|
||||
@@ -185,13 +200,15 @@
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="cmdb-preference-footor-unsubscribed">
|
||||
<a
|
||||
@click="handleSubscribeCIType(item)"
|
||||
class="cmdb-preference-footor-unsubscribed-item"
|
||||
>
|
||||
<ops-icon type="cmdb-ci" />{{ $t('cmdb.preference.subCITable') }}
|
||||
</a>
|
||||
<span class="cmdb-preference-footor-unsubscribed-gap"></span>
|
||||
<template v-if="!enableAutoSub">
|
||||
<a
|
||||
@click="handleSubscribeCIType(item)"
|
||||
class="cmdb-preference-footor-unsubscribed-item"
|
||||
>
|
||||
<ops-icon type="cmdb-ci" />{{ $t('cmdb.preference.subCITable') }}
|
||||
</a>
|
||||
<span class="cmdb-preference-footor-unsubscribed-gap"></span>
|
||||
</template>
|
||||
<a
|
||||
@click="openSubscribeSetting(item, '2')"
|
||||
class="cmdb-preference-footor-unsubscribed-item"
|
||||
@@ -209,17 +226,21 @@
|
||||
ref="subscribeSetting"
|
||||
@reload="
|
||||
() => {
|
||||
resetRoute()
|
||||
initData()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<AutoSubscribe
|
||||
ref="autoSubRef"
|
||||
:ciType="citypeData"
|
||||
:autoSub="autoSub"
|
||||
@ok="initData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import router, { resetRouter } from '@/router'
|
||||
import store from '@/store'
|
||||
import { mapState } from 'vuex'
|
||||
import moment from 'moment'
|
||||
import draggable from 'vuedraggable'
|
||||
@@ -238,10 +259,12 @@ import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting
|
||||
import { getCIAdcStatistics } from '../../api/ci'
|
||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
||||
import { SUB_NET_CITYPE_NAME, SCOPE_CITYPE_NAME, ADDRESS_CITYPE_NAME } from '../ipam/constants.js'
|
||||
import AutoSubscribe from './components/autoSubscribe.vue'
|
||||
import { getAutoSubscription } from '@/modules/cmdb/api/preference.js'
|
||||
|
||||
export default {
|
||||
name: 'Preference',
|
||||
components: { CollapseTransition, SubscribeSetting, draggable, OpsMoveIcon, Ellipsis },
|
||||
components: { CollapseTransition, SubscribeSetting, draggable, OpsMoveIcon, Ellipsis, AutoSubscribe },
|
||||
data() {
|
||||
return {
|
||||
citypeData: [],
|
||||
@@ -253,6 +276,7 @@ export default {
|
||||
type_id2users: {},
|
||||
myPreferences: [],
|
||||
searchValue: '',
|
||||
autoSub: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -275,11 +299,19 @@ export default {
|
||||
}
|
||||
return this.citypeData
|
||||
},
|
||||
enableAutoSub() {
|
||||
return this?.autoSub?.enabled ?? false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getCITypes(true)
|
||||
this.getAutoSubscription()
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
this.getCITypes()
|
||||
this.getAutoSubscription()
|
||||
},
|
||||
async getCITypes(isInit = false) {
|
||||
const [ciTypeGroup, pref, pref2, statistics] = await Promise.all([
|
||||
getCITypeGroups({ need_other: true }),
|
||||
@@ -350,6 +382,12 @@ export default {
|
||||
}, 300)
|
||||
}
|
||||
},
|
||||
|
||||
async getAutoSubscription() {
|
||||
const res = await getAutoSubscription()
|
||||
this.autoSub = res || {}
|
||||
},
|
||||
|
||||
getsubscribedDays(item) {
|
||||
const subscribedTime = this.self.type_id2subs_time[item.id]
|
||||
moment.duration(moment().diff(moment(subscribedTime)))
|
||||
@@ -396,21 +434,11 @@ export default {
|
||||
}
|
||||
}
|
||||
that.$message.success(that.$t('cmdb.preference.cancelSubSuccess'))
|
||||
that.resetRoute()
|
||||
that.initData()
|
||||
})
|
||||
},
|
||||
})
|
||||
},
|
||||
resetRoute() {
|
||||
const roles = store.getters.roles
|
||||
store.dispatch('GenerateRoutes', { roles }, { root: true }).then(() => {
|
||||
resetRouter()
|
||||
this.$nextTick(() => {
|
||||
router.addRoutes(store.getters.appRoutes)
|
||||
this.getCITypes()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
async handleSubscribeCIType(ciType) {
|
||||
try {
|
||||
@@ -433,7 +461,7 @@ export default {
|
||||
subscribeList
|
||||
)
|
||||
this.$message.success(this.$t('cmdb.components.subSuccess'))
|
||||
this.resetRoute()
|
||||
this.initData()
|
||||
} catch (error) {
|
||||
console.error('handleSubscribeCIType failed', error)
|
||||
this.$message.success(this.$t('cmdb.components.subFailed'))
|
||||
@@ -461,7 +489,7 @@ export default {
|
||||
})
|
||||
preferenceCitypeOrder({ type_ids: typeIds, is_tree: false })
|
||||
.then(() => {
|
||||
this.resetRoute()
|
||||
this.initData()
|
||||
})
|
||||
.catch(() => {
|
||||
this.getCITypes(false)
|
||||
@@ -487,13 +515,17 @@ export default {
|
||||
preferenceCitypeOrder({ type_ids: typeIds, is_tree: isTree })
|
||||
.then(() => {
|
||||
if (!isTree) {
|
||||
this.resetRoute()
|
||||
this.initData()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.getCITypes(false)
|
||||
})
|
||||
},
|
||||
|
||||
openAutoSubModal() {
|
||||
this.$refs.autoSubRef.open()
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -629,6 +661,45 @@ export default {
|
||||
height: 100%;
|
||||
padding-top: 24px;
|
||||
|
||||
&-header {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&-search {
|
||||
width: 300px;
|
||||
margin-right: 14px;
|
||||
}
|
||||
|
||||
&-auto {
|
||||
background: linear-gradient(90deg, #16D9E3 0%, #30C7EC 47%, #46AEF7 100%);
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
padding: 0 12px;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
span {
|
||||
margin-left: 4px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&_enable {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-group-title {
|
||||
width: 300px;
|
||||
margin-bottom: 20px;
|
||||
@@ -651,7 +722,7 @@ export default {
|
||||
.cmdb-preference-type {
|
||||
display: inline-block;
|
||||
width: 195px;
|
||||
height: 155px;
|
||||
height: 127px;
|
||||
border-radius: @border-radius-box;
|
||||
background-color: #fff;
|
||||
box-shadow: ~'0px 2px 8px @{primary-color}15';
|
||||
|
Reference in New Issue
Block a user