mirror of
https://github.com/veops/cmdb.git
synced 2025-09-01 18:03:09 +08:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
23cded688e | ||
|
d78cb0f94e | ||
|
c915b46374 | ||
|
6112dc83ef | ||
|
0603783574 |
@@ -308,6 +308,8 @@ class AutoDiscoveryCITypeCRUD(DBMixin):
|
||||
if new_last_update_at < __last_update_at:
|
||||
new_last_update_at = __last_update_at
|
||||
|
||||
new_last_update_at = new_last_update_at or ad_rules_updated_at
|
||||
|
||||
write_ad_rule_sync_history.apply_async(args=(result, oneagent_id, oneagent_name, datetime.datetime.now()),
|
||||
queue=CMDB_QUEUE)
|
||||
if not last_update_at or new_last_update_at > last_update_at:
|
||||
@@ -693,6 +695,11 @@ class AutoDiscoveryCICRUD(DBMixin):
|
||||
stdout="delete resource: {}".format(unique_value))
|
||||
# TODO: delete ci
|
||||
|
||||
@classmethod
|
||||
def get_instance_by_id(cls, adc_id):
|
||||
adc = cls.cls.get_by_id(adc_id) or abort(404, ErrFormat.adc_not_found)
|
||||
return adc.instance
|
||||
|
||||
@classmethod
|
||||
def accept(cls, adc, adc_id=None, nickname=None):
|
||||
if adc_id is not None:
|
||||
@@ -725,7 +732,7 @@ class AutoDiscoveryCICRUD(DBMixin):
|
||||
from api.tasks.cmdb import add_net_device_ports
|
||||
add_net_device_ports.apply_async(args=(ci_id, adc.instance['ports']),
|
||||
queue=CMDB_QUEUE)
|
||||
|
||||
|
||||
adc.update(is_accept=True,
|
||||
accept_by=nickname or current_user.nickname,
|
||||
accept_time=datetime.datetime.now(),
|
||||
|
@@ -205,12 +205,14 @@ class AutoDiscoveryCITypeRelationView(APIView):
|
||||
class AutoDiscoveryCIView(APIView):
|
||||
url_prefix = ("/adc", "/adc/<int:adc_id>", "/adc/ci_types/<int:type_id>/attributes", "/adc/ci_types")
|
||||
|
||||
def get(self, type_id=None):
|
||||
def get(self, type_id=None, adc_id=None):
|
||||
if "attributes" in request.url:
|
||||
return self.jsonify(AutoDiscoveryCICRUD.get_attributes_by_type_id(type_id))
|
||||
elif "ci_types" in request.url:
|
||||
if "ci_types" in request.url:
|
||||
need_other = request.values.get("need_other")
|
||||
return self.jsonify(AutoDiscoveryCICRUD.get_ci_types(need_other))
|
||||
if adc_id is not None:
|
||||
return self.jsonify(AutoDiscoveryCICRUD.get_instance_by_id(adc_id))
|
||||
|
||||
page = get_page(request.values.pop('page', 1))
|
||||
page_size = get_page_size(request.values.pop('page_size', None))
|
||||
|
@@ -138,6 +138,14 @@ export function getAdc(params) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getAdcById(id, params) {
|
||||
return axios({
|
||||
url: `v0.1/adc/${id}`,
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteAdc(adc_id) {
|
||||
return axios({
|
||||
url: `v0.1/adc/${adc_id}`,
|
||||
|
@@ -686,7 +686,8 @@ if __name__ == "__main__":
|
||||
tabCustom: 'Custom',
|
||||
tabConfig: 'Configured',
|
||||
addConfig: 'Add Config',
|
||||
configErrTip: 'Please select config'
|
||||
configErrTip: 'Please select config',
|
||||
viewRawData: 'View Raw Data'
|
||||
},
|
||||
ci: {
|
||||
attributeDesc: 'Attribute Description',
|
||||
|
@@ -685,7 +685,8 @@ if __name__ == "__main__":
|
||||
tabCustom: '自定义',
|
||||
tabConfig: '已有配置',
|
||||
addConfig: '添加配置',
|
||||
configErrTip: '请选择配置'
|
||||
configErrTip: '请选择配置',
|
||||
viewRawData: '查看原始数据'
|
||||
},
|
||||
ci: {
|
||||
attributeDesc: '查看属性配置',
|
||||
|
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div class="ci-types-wrap" :style="{ height: `${windowHeight - 96}px` }">
|
||||
<div v-if="!CITypeGroups.length" class="ci-types-empty">
|
||||
<div v-if="pageLoading" class="ci-types-loading">
|
||||
<a-spin size="large" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="!CITypeGroups.length" class="ci-types-empty">
|
||||
<a-empty :image="emptyImage" description=""></a-empty>
|
||||
<a-button icon="plus" size="small" type="primary" @click="handleClickAddGroup">{{
|
||||
$t('cmdb.ciType.addGroup')
|
||||
@@ -485,6 +489,7 @@ export default {
|
||||
|
||||
searchValue: '',
|
||||
modelExportVisible: false,
|
||||
pageLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -578,7 +583,7 @@ export default {
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
async mounted() {
|
||||
this.getAllDepAndEmployee()
|
||||
const _currentId = localStorage.getItem('ops_cityps_currentId')
|
||||
if (_currentId) {
|
||||
@@ -587,7 +592,11 @@ export default {
|
||||
searchResourceType({ page_size: 9999, app_id: 'cmdb' }).then((res) => {
|
||||
this.resource_type = { groups: res.groups, id2perms: res.id2perms }
|
||||
})
|
||||
this.loadCITypes(!_currentId, true)
|
||||
|
||||
this.pageLoading = true
|
||||
await this.loadCITypes(!_currentId, true)
|
||||
this.pageLoading = false
|
||||
|
||||
this.getAttributes()
|
||||
},
|
||||
methods: {
|
||||
@@ -1082,6 +1091,12 @@ export default {
|
||||
<style lang="less" scoped>
|
||||
.ci-types-wrap {
|
||||
margin: 0 0 -24px 0;
|
||||
|
||||
.ci-types-loading {
|
||||
text-align: center;
|
||||
padding-top: 150px;
|
||||
}
|
||||
|
||||
.ci-types-empty {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
|
@@ -239,6 +239,8 @@
|
||||
<a-form-item>
|
||||
<a-select
|
||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip4')"
|
||||
optionFilterProp="title"
|
||||
show-search
|
||||
allowClear
|
||||
v-model="item.parentAttrId"
|
||||
>
|
||||
@@ -250,6 +252,7 @@
|
||||
'parent'
|
||||
)"
|
||||
:key="attr.id"
|
||||
:title="attr.alias || attr.name"
|
||||
>
|
||||
{{ attr.alias || attr.name }}
|
||||
</a-select-option>
|
||||
@@ -263,6 +266,8 @@
|
||||
<a-form-item>
|
||||
<a-select
|
||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip5')"
|
||||
optionFilterProp="title"
|
||||
show-search
|
||||
allowClear
|
||||
v-model="item.childAttrId"
|
||||
>
|
||||
@@ -274,6 +279,7 @@
|
||||
'child'
|
||||
)"
|
||||
:key="attr.id"
|
||||
:title="attr.alias || attr.name"
|
||||
>
|
||||
{{ attr.alias || attr.name }}
|
||||
</a-select-option>
|
||||
|
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="$t('cmdb.ad.viewRawData')"
|
||||
:visible="visible"
|
||||
wrapClassName="ci-json-editor"
|
||||
width="50%"
|
||||
:footer="null"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<vue-json-editor
|
||||
v-model="jsonData"
|
||||
:style="{ '--custom-height': `${windowHeight - 300}px` }"
|
||||
:showBtns="false"
|
||||
:mode="'code'"
|
||||
lang="zh"
|
||||
/>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import vueJsonEditor from 'vue-json-editor'
|
||||
|
||||
export default {
|
||||
name: 'RawDataModal',
|
||||
components: { vueJsonEditor },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
jsonData: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
windowHeight() {
|
||||
return this.$store.state.windowHeight
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
open(jsonData) {
|
||||
this.visible = true
|
||||
this.jsonData = jsonData
|
||||
},
|
||||
handleCancel() {
|
||||
this.visible = false
|
||||
this.jsonData = {}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ci-json-editor {
|
||||
.jsoneditor-outer {
|
||||
height: var(--custom-height) !important;
|
||||
border: 1px solid #2f54eb;
|
||||
}
|
||||
div.jsoneditor-menu {
|
||||
background-color: #2f54eb;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -92,15 +92,13 @@
|
||||
:width="col.width"
|
||||
:sortable="col.sortable"
|
||||
>
|
||||
<template v-if="col.value_type === '6' || col.is_password" #default="{row}">
|
||||
<template #default="{row}">
|
||||
<PasswordField
|
||||
v-if="col.is_password"
|
||||
:password="row[col.field]"
|
||||
/>
|
||||
<span
|
||||
v-else-if="col.value_type === '6' && row[col.field]"
|
||||
>
|
||||
{{ row[col.field] }}
|
||||
<span>
|
||||
{{ typeof row[col.field] === 'object' ? JSON.stringify(row[col.field]) : row[col.field] }}
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
@@ -137,7 +135,7 @@
|
||||
></vxe-column>
|
||||
<vxe-column
|
||||
:title="$t('operation')"
|
||||
v-bind="columns.length ? { width: '60px' } : { minWidth: '60px' }"
|
||||
v-bind="columns.length ? { width: '100px' } : { minWidth: '100px' }"
|
||||
align="center"
|
||||
fixed="right"
|
||||
>
|
||||
@@ -146,6 +144,9 @@
|
||||
<a-tooltip :title="$t('cmdb.ad.accept')">
|
||||
<a v-if="!row.is_accept" @click="accept(row)"><ops-icon type="cmdb-manual_warehousing"/></a>
|
||||
</a-tooltip>
|
||||
<a-tooltip :title="$t('cmdb.ad.viewRawData')">
|
||||
<a @click="viewADC(row)"><a-icon type="eye"/></a>
|
||||
</a-tooltip>
|
||||
<a :style="{ color: 'red' }" @click="deleteADC(row)"><a-icon type="delete"/></a>
|
||||
</a-space>
|
||||
</template>
|
||||
@@ -175,6 +176,8 @@
|
||||
</p>
|
||||
</a-modal>
|
||||
</div>
|
||||
|
||||
<RawDataModal ref="rawDataModalRef" />
|
||||
</template>
|
||||
</TwoColumnLayout>
|
||||
</template>
|
||||
@@ -185,6 +188,7 @@ import XEUtils from 'xe-utils'
|
||||
import TwoColumnLayout from '@/components/TwoColumnLayout'
|
||||
import AdcCounter from './components/adcCounter.vue'
|
||||
import PasswordField from './components/passwordField.vue'
|
||||
import RawDataModal from './components/rawDataModal.vue'
|
||||
|
||||
import {
|
||||
getADCCiTypes,
|
||||
@@ -192,7 +196,8 @@ import {
|
||||
updateADCAccept,
|
||||
getADCCiTypesAttrs,
|
||||
deleteAdc,
|
||||
getAdcExecHistories
|
||||
getAdcExecHistories,
|
||||
getAdcById
|
||||
} from '../../api/discovery'
|
||||
import { getCITableColumns } from '../../utils/helper'
|
||||
|
||||
@@ -201,7 +206,8 @@ export default {
|
||||
components: {
|
||||
TwoColumnLayout,
|
||||
AdcCounter,
|
||||
PasswordField
|
||||
PasswordField,
|
||||
RawDataModal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -352,6 +358,12 @@ export default {
|
||||
onCancel() {},
|
||||
})
|
||||
},
|
||||
|
||||
async viewADC(row) {
|
||||
const res = await getAdcById(row.id)
|
||||
this.$refs.rawDataModalRef.open(res || {})
|
||||
},
|
||||
|
||||
async batchAccept() {
|
||||
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
||||
await updateADCAccept(this.selectedRowKeys[i])
|
||||
|
@@ -77,12 +77,15 @@
|
||||
<a-form-item>
|
||||
<a-select
|
||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip4')"
|
||||
optionFilterProp="title"
|
||||
show-search
|
||||
allowClear
|
||||
v-model="item.parentAttrId"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="attr in filterAttributes(modalParentAttributes, item.childAttrId, modalChildAttributes, 'parent')"
|
||||
:key="attr.id"
|
||||
:title="attr.alias || attr.name"
|
||||
>
|
||||
{{ attr.alias || attr.name }}
|
||||
</a-select-option>
|
||||
@@ -96,12 +99,15 @@
|
||||
<a-form-item>
|
||||
<a-select
|
||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip5')"
|
||||
optionFilterProp="title"
|
||||
show-search
|
||||
allowClear
|
||||
v-model="item.childAttrId"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="attr in filterAttributes(modalChildAttributes, item.parentAttrId, modalParentAttributes, 'child')"
|
||||
:key="attr.id"
|
||||
:title="attr.alias || attr.name"
|
||||
>
|
||||
{{ attr.alias || attr.name }}
|
||||
</a-select-option>
|
||||
|
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div :style="{ marginBottom: '-24px' }">
|
||||
<div v-if="!subscribeTreeViewCiTypesLoading && subscribeTreeViewCiTypes.length === 0">
|
||||
<div v-if="subscribeTreeViewCiTypesLoading" class="page-loading">
|
||||
<a-spin size="large" />
|
||||
</div>
|
||||
<div v-else-if="subscribeTreeViewCiTypes.length === 0">
|
||||
<a-alert banner>
|
||||
<template #message>
|
||||
<span>{{ $t('cmdb.preference.tips1') }}</span>
|
||||
@@ -638,7 +641,11 @@ export default {
|
||||
},
|
||||
columnDrop() {
|
||||
this.$nextTick(() => {
|
||||
const xTable = this.$refs.xTable.getVxetableRef()
|
||||
const xTable = this.$refs?.xTable?.getVxetableRef?.()
|
||||
if (!xTable) {
|
||||
return
|
||||
}
|
||||
|
||||
this.sortable = Sortable.create(
|
||||
xTable.$el.querySelector('.body--wrapper>.vxe-table--header .vxe-header--row'),
|
||||
{
|
||||
@@ -1015,6 +1022,11 @@ export default {
|
||||
|
||||
<style lang="less">
|
||||
@import '../index.less';
|
||||
.page-loading {
|
||||
text-align: center;
|
||||
padding-top: 150px;
|
||||
}
|
||||
|
||||
.tree-views {
|
||||
width: 100%;
|
||||
height: calc(100% - 32px);
|
||||
|
Reference in New Issue
Block a user