feat(ui): topology view (#525)

This commit is contained in:
pycook
2024-05-28 20:03:10 +08:00
committed by GitHub
parent 2d3a290aa3
commit 729a616282
17 changed files with 2857 additions and 15 deletions

View File

@@ -2,11 +2,12 @@ import { axios } from '@/utils/request'
const urlPrefix = '/v0.1'
export function searchCI(params) {
export function searchCI(params, isShowMessage = true) {
return axios({
url: urlPrefix + `/ci/s`,
method: 'GET',
params: params
params: params,
isShowMessage
})
}

View File

@@ -0,0 +1,110 @@
import { axios } from '@/utils/request'
const urlPrefix = '/v0.1'
export function getTopoGroups() {
return axios({
url: `${urlPrefix}/topology_views`,
method: 'GET',
})
}
export function getTopoView(_id) {
return axios({
url: `${urlPrefix}/topology_views/${_id}`,
method: 'GET',
})
}
export function postTopoGroup(data) {
return axios({
url: `${urlPrefix}/topology_views/groups`,
method: 'POST',
data: data
})
}
export function putTopoGroupByGId(gid, data) {
return axios({
url: `${urlPrefix}/topology_views/groups/${gid}`,
method: 'PUT',
data: data
})
}
export function putTopoGroupsOrder(data) {
return axios({
url: `${urlPrefix}/topology_views/groups/order`,
method: 'PUT',
data: data
})
}
export function deleteTopoGroup(gid, data) {
return axios({
url: `${urlPrefix}/topology_views/groups/${gid}`,
method: 'DELETE',
data: data
})
}
export function addTopoView(data) {
return axios({
url: `${urlPrefix}/topology_views`,
method: 'POST',
data: data
})
}
export function updateTopoView(_id, data) {
return axios({
url: `${urlPrefix}/topology_views/${_id}`,
method: 'PUT',
data: data
})
}
export function deleteTopoView(_id) {
return axios({
url: `${urlPrefix}/topology_views/${_id}`,
method: 'DELETE',
})
}
export function getRelationsByTypeId(_id) {
return axios({
url: `${urlPrefix}/topology_views/relations/ci_types/${_id}`,
method: 'GET',
})
}
export function previewTopoView(params) {
return axios({
url: `${urlPrefix}/topology_views/preview`,
method: 'POST',
data: params,
})
}
export function showTopoView(_id) {
return axios({
url: `${urlPrefix}/topology_views/${_id}/view`,
method: 'GET',
})
}
export function grantTopologyView(viewId, rid, data) {
return axios({
url: `/v0.1/topology_views/${viewId}/roles/${rid}/grant`,
method: 'POST',
data: data
})
}
export function revokeTopologyView(viewId, rid, data) {
return axios({
url: `/v0.1/topology_views/${viewId}/roles/${rid}/revoke`,
method: 'POST',
data: data
})
}

View File

@@ -57,6 +57,20 @@
:addedRids="addedRids"
/>
</template>
<template v-if="cmdbGrantType.includes('TopologyView')">
<div class="cmdb-grant-title">{{ resourceTypeName }}{{ $t('cmdb.components.perm') }}</div>
<TopologyViewGrant
:resourceTypeName="resourceTypeName"
:tableData="tableData"
:viewId="CITypeId"
grantType="TopologyView"
@grantDepart="grantDepart"
@grantRole="grantRole"
@getTableData="getTableData"
ref="grantTopologyView"
:addedRids="addedRids"
/>
</template>
<GrantModal ref="grantModal" @handleOk="handleOk" />
<ReadGrantModal ref="readGrantModal" :CITypeId="CITypeId" @updateTableDataRead="updateTableDataRead" />
@@ -72,11 +86,12 @@ import { getResourcePerms } from '@/modules/acl/api/permission'
import GrantModal from './grantModal.vue'
import ReadGrantModal from './readGrantModal'
import RelationViewGrant from './relationViewGrant.vue'
import TopologyViewGrant from './topologyViewGrant.vue'
import { getCITypeGroupById, ciTypeFilterPermissions } from '../../api/CIType'
export default {
name: 'GrantComp',
components: { CiTypeGrant, TypeRelationGrant, RelationViewGrant, GrantModal, ReadGrantModal },
components: { CiTypeGrant, TypeRelationGrant, RelationViewGrant, TopologyViewGrant, GrantModal, ReadGrantModal },
props: {
CITypeId: {
type: Number,
@@ -291,6 +306,20 @@ export default {
})
)
}
if (grantType === 'TopologyView') {
this.tableData.unshift(
...rids.map(({ rid, name }) => {
return {
rid,
name,
read: false,
update: false,
delete: false,
grant: false,
}
})
)
}
this.addedRids = rids
this.$nextTick(() => {
setTimeout(() => {

View File

@@ -0,0 +1,102 @@
<template>
<div class="topology-view-grant">
<vxe-table
ref="xTable"
size="mini"
stripe
class="ops-stripe-table"
:data="tableData"
:max-height="`${tableHeight}px`"
:scroll-y="{enabled: true}"
:row-style="(params) => getCurrentRowStyle(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
<template #default="{row}">
<a-checkbox @change="(e) => handleChange(e, col, row)" v-model="row[col]"></a-checkbox>
</template>
</vxe-column>
</vxe-table>
<a-space>
<span class="grant-button" @click="grantDepart">{{ $t('cmdb.components.grantUser') }}</span>
<span class="grant-button" @click="grantRole">{{ $t('cmdb.components.grantRole') }}</span>
</a-space>
</div>
</template>
<script>
import { permMap } from './constants.js'
import { grantTopologyView, revokeTopologyView } from '@/modules/cmdb/api/topology.js'
import { getCurrentRowStyle } from './utils'
export default {
name: 'TopologyViewGrant',
inject: ['loading', 'isModal'],
props: {
viewId: {
type: Number,
default: null,
},
resourceTypeName: {
type: String,
default: '',
},
tableData: {
type: Array,
default: () => [],
},
grantType: {
type: String,
default: 'relation_view',
},
addedRids: {
type: Array,
default: () => [],
},
},
data() {
return {
columns: ['read', 'update', 'delete', 'grant'],
}
},
computed: {
windowHeight() {
return this.$store.state.windowHeight
},
tableHeight() {
if (this.isModal) {
return (this.windowHeight - 104) / 2
}
return (this.windowHeight - 104) / 2 - 116
},
permMap() {
return permMap()
}
},
methods: {
getCurrentRowStyle,
grantDepart() {
this.$emit('grantDepart', this.grantType)
},
grantRole() {
this.$emit('grantRole', this.grantType)
},
handleChange(e, col, row) {
if (e.target.checked) {
grantTopologyView(this.viewId, row.rid, { perms: [col], name: this.resourceTypeName }).catch(() => {
this.$emit('getTableData')
})
} else {
revokeTopologyView(this.viewId, row.rid, { perms: [col], name: this.resourceTypeName }).catch(() => {
this.$emit('getTableData')
})
}
},
},
}
</script>
<style lang="less" scoped>
.topology-view-grant {
padding: 10px 0;
}
</style>

View File

@@ -4,6 +4,7 @@ const cmdb_en = {
configTable: 'Config Table',
menu: {
views: 'Views',
topologyView: 'Topology Views',
resources: 'Resources',
config: 'Configuration',
backend: 'Management',
@@ -563,6 +564,30 @@ if __name__ == "__main__":
tree: {
tips1: 'Please go to Preference page first to complete your subscription!',
subSettings: 'Settings',
}
},
topo: {
addTopoView: 'Add Topology View',
editTopoView: 'Edit Topology View',
addTopoViewInGroup: 'Define topology view under grouping',
groupRequired: 'Please select a group first or create a group',
viewName: 'Title',
viewNamePlaceholder: 'Please enter a title for the topology view',
inputNameTips: 'Title is required',
centralNodeType: 'Central Node Model',
filterInstances: 'Central Node Instances',
typeRequired: 'Central Node Model is required',
instancesRequired: 'instances are required',
path: 'Path',
aggregationCount: 'Aggregation Count',
aggreationCountTip: 'When the number of child nodes > the number of aggregations, paging display',
preview: 'Preivew',
noData: 'No data',
edit: 'Edit',
delete: 'Delete',
searchPlaceholder: 'Search topology view',
confirmDeleteView: 'Are you sure you want to delete this view ?',
noInstancePerm: 'You do not have read permissions for this instance',
noPreferenceAttributes: 'This instance has no subscription attributes or no default displayed attributes',
},
}
export default cmdb_en

View File

@@ -4,6 +4,7 @@ const cmdb_zh = {
configTable: '配置表格',
menu: {
views: '视图',
topologyView: '拓扑视图',
resources: '资源',
config: '配置',
backend: '管理',
@@ -563,6 +564,30 @@ if __name__ == "__main__":
tree: {
tips1: '请先到 我的订阅 页面完成订阅!',
subSettings: '订阅设置',
}
},
topo: {
addTopoView: '新增拓扑视图',
editTopoView: '编辑拓扑视图',
addTopoViewInGroup: '在分组下定义拓扑视图',
groupRequired: '请先选择分组或者创建分组',
viewName: '标题',
viewNamePlaceholder: '请输入拓扑视图的标题',
inputNameTips: '必须输入标题',
centralNodeType: '中心节点模型',
filterInstances: '中心节点实例',
typeRequired: '必须要选择中心节点模型',
instancesRequired: '实例必须要选择',
path: '路径选择',
aggregationCount: '聚合数',
aggreationCountTip: '当子节点数 > 聚合数 则进行分页展示',
preview: '预览',
noData: '没有数据',
edit: '编辑',
delete: '删除',
searchPlaceholder: '搜索拓扑视图',
confirmDeleteView: '您确定要删除该视图吗?',
noInstancePerm: '您没有该实例的查看权限',
noPreferenceAttributes: '该实例没有订阅属性或者没有默认展示的属性',
},
}
export default cmdb_zh

View File

@@ -16,6 +16,12 @@ const genCmdbRoutes = async () => {
meta: { title: 'dashboard', icon: 'ops-cmdb-dashboard', selectedIcon: 'ops-cmdb-dashboard', keepAlive: false },
component: () => import('../views/dashboard/index_v2.vue')
},
{
path: '/cmdb/topoviews',
name: 'cmdb_topology_views',
meta: { title: 'cmdb.menu.topologyView', appName: 'cmdb', icon: 'ops-topology_view', selectedIcon: 'ops-topology_view', keepAlive: false },
component: () => import('../views/topology_view/index.vue')
},
{
path: '/cmdb/disabled1',
name: 'cmdb_disabled1',

View File

@@ -689,7 +689,7 @@ export default {
content: that.$t('cmdb.ciType.confirmDeleteGroup', { groupName: `${g.name}` }),
onOk() {
deleteCITypeGroup(g.id).then((res) => {
that.$message.info(that.$t('deleteSuccess'))
that.$message.success(that.$t('deleteSuccess'))
that.loadCITypes(true)
})
},

View File

@@ -274,8 +274,8 @@ export default {
this.ciTypes = res.ci_types
})
},
getCIType(typeId) {
getCIType(typeId).then((res) => {
async getCIType(typeId) {
await getCIType(typeId).then((res) => {
this.ciTypes = res.ci_types
})
},

File diff suppressed because it is too large Load Diff