mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-13 11:24:17 +00:00
perf: update pam
This commit is contained in:
@@ -71,6 +71,7 @@
|
||||
<el-tooltip v-if="opt.tip" :content="opt.tip" :open-delay="500" placement="top">
|
||||
<i class="el-icon-warning-outline" />
|
||||
</el-tooltip>
|
||||
<span v-if="data.helpText">{{ data.helpText }}</span>
|
||||
</el-checkbox>
|
||||
<!-- WARNING: radio 用 label 属性来表示 value 的含义 -->
|
||||
<!-- FYI: radio 的 value 属性可以在没有 radio-group 时用来关联到同一个 v-model -->
|
||||
@@ -87,7 +88,7 @@
|
||||
</el-radio>
|
||||
</template>
|
||||
</custom-component>
|
||||
<div v-if="data.helpText" class="help-block">
|
||||
<div v-if="data.helpText" :class="data.type" class="help-block">
|
||||
<el-alert
|
||||
v-if="data.helpText.startsWith('!')"
|
||||
:closable="false"
|
||||
@@ -315,6 +316,10 @@ export default {
|
||||
::v-deep .el-alert__icon {
|
||||
font-size: 16px
|
||||
}
|
||||
|
||||
&.checkbox {
|
||||
//display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.help-tip-icon {
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
<template>
|
||||
<DataZTree ref="dataztree" :setting="treeSetting" class="data-z-tree" v-on="$listeners">
|
||||
<slot v-if="treeSetting.hasRightMenu" slot="rMenu">
|
||||
<li v-if="treeSetting.showCreate" id="m_create" class="rmenu" tabindex="-1" @click="createTreeNode">
|
||||
<i class="fa fa-plus-square-o" /> {{ this.$t('CreateNode') }}
|
||||
</li>
|
||||
<li v-if="treeSetting.showUpdate" id="m_edit" class="rmenu" tabindex="-1" @click="editTreeNode">
|
||||
<i class="fa fa-pencil-square-o" /> {{ this.$t('RenameNode') }}
|
||||
</li>
|
||||
<li v-if="treeSetting.showDelete" id="m_del" class="rmenu" tabindex="-1" @click="removeTreeNode">
|
||||
<i class="fa fa-minus-square" /> {{ this.$t('DeleteNode') }}
|
||||
</li>
|
||||
<slot slot="rMenu">
|
||||
<div v-if="menu && menu.length > 0">
|
||||
<span v-for="item in menu" :key="item.id">
|
||||
<li
|
||||
v-if="hasMenuItem(item)"
|
||||
:id="item.id"
|
||||
:key="item.id"
|
||||
:class="{ 'disabled': checkDisabled(item) }"
|
||||
class="rmenu"
|
||||
tabindex="-1"
|
||||
@click="onMenuItemClick(item)"
|
||||
>
|
||||
<Icon :icon="item.icon" class="icon" /> {{ item.name }}
|
||||
</li>
|
||||
<li v-if="item.divided" class="divider" />
|
||||
</span>
|
||||
</div>
|
||||
<slot name="rMenu" />
|
||||
</slot>
|
||||
</DataZTree>
|
||||
@@ -17,13 +24,15 @@
|
||||
|
||||
<script>
|
||||
import DataZTree from '../DataZTree/index.vue'
|
||||
import Icon from '@/components/Widgets/Icon'
|
||||
import $ from '@/utils/jquery-vendor'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AutoDataZTree',
|
||||
components: {
|
||||
DataZTree
|
||||
DataZTree,
|
||||
Icon
|
||||
},
|
||||
props: {
|
||||
setting: {
|
||||
@@ -34,7 +43,32 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultMenu: [
|
||||
{
|
||||
id: 'm_create',
|
||||
name: this.$t('CreateNode'),
|
||||
icon: 'fa-plus-square-o',
|
||||
callback: this.createTreeNode,
|
||||
has: () => this.setting.showCreate
|
||||
},
|
||||
{
|
||||
id: 'm_edit',
|
||||
name: this.$t('RenameNode'),
|
||||
icon: 'fa-pencil-square-o',
|
||||
callback: this.editTreeNode,
|
||||
has: () => this.setting.showUpdate
|
||||
},
|
||||
{
|
||||
id: 'm_del',
|
||||
name: this.$t('DeleteNode'),
|
||||
icon: 'fa-minus-square',
|
||||
callback: this.removeTreeNode,
|
||||
has: () => this.setting.showDelete
|
||||
}
|
||||
],
|
||||
defaultSetting: {
|
||||
showDefaultMenu: true,
|
||||
showMenu: false,
|
||||
showCreate: true,
|
||||
showDelete: true,
|
||||
showUpdate: true,
|
||||
@@ -80,12 +114,49 @@ export default {
|
||||
},
|
||||
rMenu() {
|
||||
return this.$refs.dataztree.rMenu
|
||||
},
|
||||
menu() {
|
||||
let menu = []
|
||||
if (this.setting.showDefaultMenu) {
|
||||
menu = menu.concat(this.defaultMenu)
|
||||
}
|
||||
if (this.setting.menu && this.setting.menu.length > 0) {
|
||||
menu = menu.concat(this.setting.menu)
|
||||
}
|
||||
return menu
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
$('body').unbind('mousedown')
|
||||
},
|
||||
methods: {
|
||||
checkDisabled(item) {
|
||||
let disabled = item.disabled
|
||||
if (typeof disabled === 'function') {
|
||||
disabled = disabled(this.currentNode)
|
||||
}
|
||||
if (typeof disabled === 'undefined') {
|
||||
disabled = false
|
||||
}
|
||||
return disabled
|
||||
},
|
||||
hasMenu(node) {
|
||||
return false
|
||||
},
|
||||
hasMenuItem(item) {
|
||||
let has = item.has
|
||||
if (typeof has === 'function') {
|
||||
has = has(this.currentNode)
|
||||
}
|
||||
if (typeof has === 'undefined') {
|
||||
has = true
|
||||
}
|
||||
return has
|
||||
},
|
||||
onMenuItemClick(item) {
|
||||
item.callback(this.currentNode)
|
||||
this.hideRMenu()
|
||||
},
|
||||
onAsyncSuccess(event, treeId, treeNode, msg) {
|
||||
const nodes = JSON.parse(msg)
|
||||
nodes.forEach((node) => {
|
||||
@@ -115,7 +186,7 @@ export default {
|
||||
if (this.rMenu) this.rMenu.css({ 'visibility': 'hidden' })
|
||||
$('body').unbind('mousedown', this.onBodyMouseDown)
|
||||
},
|
||||
// Request URL: http://localhost/api/v1/assets/assets/?node_id=d8212328-538d-41a6-bcfd-1e8cc7e3aed4&show_current_asset=null&draw=2&limit=15&offset=0&_=1587022917769
|
||||
// Request URL: http://localhost/api/v1/assets/assets/?node_id=ID&show_current_asset=null&draw=2&limit=15&offset=0&_=1587022917769
|
||||
onSelected: function(event, treeNode) {
|
||||
const show_current_asset = this.$cookie.get('show_current_asset') || '0'
|
||||
if (!this.setting.url) {
|
||||
@@ -191,6 +262,8 @@ export default {
|
||||
const offset = $(`#${zTreeID}`).offset()
|
||||
const scrollTop = document.querySelector('.treebox')?.scrollTop
|
||||
x -= offset.left
|
||||
x = x < 0 ? 0 : x
|
||||
|
||||
// Tmp
|
||||
y -= (offset.top + scrollTop) / 3 - 10
|
||||
x += document.body.scrollLeft
|
||||
@@ -199,15 +272,22 @@ export default {
|
||||
if (y + $(`#${rMenuID} ul`).height() >= window.innerHeight) {
|
||||
y -= $(`#${rMenuID} ul`).height()
|
||||
}
|
||||
y = y < 0 ? 0 : y
|
||||
|
||||
this.rMenu.css({ 'top': y + 'px', 'left': x + 'px', 'visibility': 'visible' })
|
||||
$(`#${rMenuID} ul`).show()
|
||||
$('body').bind('mousedown', this.onBodyMouseDown)
|
||||
},
|
||||
onRightClick: function(event, treeId, treeNode) {
|
||||
if (!this.setting.showMenu) {
|
||||
let showMenu = this.setting.showMenu
|
||||
if (typeof showMenu === 'function') {
|
||||
showMenu = showMenu(treeNode)
|
||||
}
|
||||
if (!showMenu) {
|
||||
return
|
||||
}
|
||||
this.currentNode = treeNode
|
||||
this.currentNodeId = treeNode.meta.data.id
|
||||
// 屏蔽收藏资产
|
||||
if (treeNode?.id === '-12') {
|
||||
return
|
||||
@@ -321,9 +401,14 @@ export default {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 15px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.data-z-tree {
|
||||
::v-deep {
|
||||
.fa {
|
||||
.icon {
|
||||
width: 10px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<a id="tree-refresh"><i class="fa fa-refresh" /></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :id="iRMenuID" class="rMenu">
|
||||
<ul class="dropdown-menu menu-actions">
|
||||
<slot name="rMenu" />
|
||||
@@ -49,8 +50,7 @@ import axiosRetry from 'axios-retry'
|
||||
|
||||
const defaultObject = {
|
||||
type: Object,
|
||||
default: () => {
|
||||
}
|
||||
default: () => ({})
|
||||
}
|
||||
export default {
|
||||
name: 'ZTree',
|
||||
@@ -90,6 +90,12 @@ export default {
|
||||
window.removeEventListener('resize', this.updateTreeHeight)
|
||||
},
|
||||
methods: {
|
||||
onMenuClick(menu) {
|
||||
if (menu.disabled) {
|
||||
return
|
||||
}
|
||||
menu.callback()
|
||||
},
|
||||
updateTreeHeight: _.debounce(function() {
|
||||
const tree = document.getElementById(this.iZTreeID)
|
||||
if (!tree) {
|
||||
@@ -106,8 +112,8 @@ export default {
|
||||
}
|
||||
}
|
||||
// 使用 table 的高度
|
||||
const ztreeRect = tree.getBoundingClientRect()
|
||||
tree.style.height = `calc(100vh - ${ztreeRect.top}px - 30px - 25px)`
|
||||
const zTreeRect = tree.getBoundingClientRect()
|
||||
tree.style.height = `calc(100vh - ${zTreeRect.top}px - 30px - 25px)`
|
||||
}, 100),
|
||||
async initTree(refresh = false) {
|
||||
const vm = this
|
||||
@@ -156,9 +162,6 @@ export default {
|
||||
if (this.treeSetting.showMenu) {
|
||||
this.rMenu = $(`#${this.iRMenuID}`)
|
||||
}
|
||||
if (this.treeSetting?.otherMenu) {
|
||||
$('.menu-actions').append(this.otherMenu)
|
||||
}
|
||||
},
|
||||
onSearch() {
|
||||
this.showTreeSearch = !this.showTreeSearch
|
||||
@@ -435,6 +438,24 @@ div.rMenu li {
|
||||
list-style: none outside none;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
font-size: 12px;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #606266;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
border: medium none;
|
||||
min-width: 160px;
|
||||
@@ -451,7 +472,8 @@ div.rMenu li {
|
||||
text-shadow: none;
|
||||
top: 100%;
|
||||
z-index: 1000;
|
||||
height: 300px;
|
||||
max-height: 320px;
|
||||
min-height: 150px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import CronTab from '@/components/Form/FormFields/CronTab/index.vue'
|
||||
import InputWithUnit from '@/components/Form/FormFields/InputWithUnit.vue'
|
||||
import store from '@/store'
|
||||
|
||||
export const strMatchValues = ['exact', 'not', 'in', 'contains', 'startswith', 'endswith', 'regex']
|
||||
export const typeMatchMapper = {
|
||||
@@ -26,3 +29,49 @@ export const attrMatchOptions = [
|
||||
{ label: i18n.t('GreatEqualThan'), value: 'gte' },
|
||||
{ label: i18n.t('LessEqualThan'), value: 'lte' }
|
||||
]
|
||||
|
||||
export const crontab = {
|
||||
type: 'cronTab',
|
||||
component: CronTab,
|
||||
label: i18n.t('Crontab'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
helpText: i18n.t('CrontabHelpText'),
|
||||
helpTip: i18n.t('CrontabHelpTip')
|
||||
}
|
||||
|
||||
const validatorInterval = (rule, value, callback) => {
|
||||
if (parseInt(value) < 1) {
|
||||
return callback(new Error(i18n.t('EnsureThisValueIsGreaterThanOrEqualTo1')))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
export const interval = {
|
||||
label: i18n.t('Interval'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
component: InputWithUnit,
|
||||
el: {
|
||||
unit: 'hour'
|
||||
},
|
||||
rules: [
|
||||
{ validator: validatorInterval }
|
||||
]
|
||||
}
|
||||
|
||||
export const is_periodic = {
|
||||
type: 'checkbox',
|
||||
hidden: (formValue) => {
|
||||
return !store.getters.hasValidLicense
|
||||
}
|
||||
}
|
||||
|
||||
export const periodicMeta = {
|
||||
is_periodic,
|
||||
interval,
|
||||
crontab
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export { default as AccountListTable } from './Apps/AccountListTable/AccountList
|
||||
export { default as AssetRelationCard } from './Apps/AssetRelationCard'
|
||||
export { default as UserConfirmDialog } from './Apps/UserConfirmDialog'
|
||||
export { default as Announcement } from './Widgets/Announcement'
|
||||
export { default as CronTab } from './Form/CronTab'
|
||||
export { default as CronTab } from './Form/FormFields/CronTab'
|
||||
export { default as Pagination } from './Table/Pagination'
|
||||
export { default as Tooltip } from './Widgets/Tooltip'
|
||||
export { default as ResourceActivity } from './Apps/ResourceActivity'
|
||||
|
||||
@@ -62,7 +62,7 @@ export default [
|
||||
},
|
||||
{
|
||||
path: 'executions',
|
||||
component: () => import('@/views/accounts/AccountDiscover/TaskDetail/TaskExecutionList.vue'),
|
||||
component: () => import('@/views/accounts/AccountDiscover/TaskExecutionList.vue'),
|
||||
name: 'AccountDiscoverTaskExecutionList',
|
||||
hidden: true,
|
||||
meta: {
|
||||
|
||||
@@ -547,8 +547,23 @@ li.rmenu i.fa {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.el-checkbox__input {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.el-checkbox__label {
|
||||
padding-left: 5px !important;
|
||||
}
|
||||
|
||||
.el-checkbox__inner {
|
||||
border-radius: 1px !important;
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
|
||||
&::after {
|
||||
left: 5px !important;
|
||||
height: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-alert.el-alert--info.is-light {
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
import { constantRoutes } from '@/router'
|
||||
import store from '@/store'
|
||||
import { openWindow } from './common'
|
||||
|
||||
let openedTaskWindow = null // 保存已打开的窗口对象
|
||||
|
||||
function openOrReuseWindow(url, windowName = 'task', windowFeatures = '', iWidth = 900, iHeight = 600) {
|
||||
const iTop = (window.screen.height - 30 - iHeight) / 2
|
||||
const iLeft = (window.screen.width - 10 - iWidth) / 2
|
||||
|
||||
// 检查窗口是否已经打开
|
||||
if (openedTaskWindow && !openedTaskWindow.closed) {
|
||||
openedTaskWindow.location.href = url // 如果窗口未关闭,更新其地址
|
||||
openedTaskWindow.focus() // 将窗口置于前台
|
||||
} else {
|
||||
// 如果窗口未打开或已关闭,创建新窗口
|
||||
openedTaskWindow = window.open(url, windowName, 'height=' + iHeight + ',width=' + iWidth + ',top=' + iTop + ',left=' + iLeft)
|
||||
}
|
||||
}
|
||||
|
||||
export function openTaskPage(taskId, taskType, taskUrl) {
|
||||
taskType = taskType || 'celery'
|
||||
if (!taskUrl) {
|
||||
taskUrl = `/core/ops/${taskType}/task/${taskId}/log/?type=${taskType}`
|
||||
}
|
||||
openWindow(taskUrl)
|
||||
openOrReuseWindow(taskUrl)
|
||||
}
|
||||
|
||||
export function checkPermission(permsRequired, permsAll) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import getChangeSecretFields from '@/views/accounts/AccountBackup/fields'
|
||||
import { encryptPassword } from '@/utils/crypto'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
|
||||
export default {
|
||||
name: 'AccountBackupUpdate',
|
||||
@@ -40,9 +41,7 @@ export default {
|
||||
categories: []
|
||||
},
|
||||
fieldsMeta: {
|
||||
is_periodic: fields.is_periodic,
|
||||
crontab: fields.crontab,
|
||||
interval: fields.interval,
|
||||
...periodicMeta,
|
||||
is_password_divided_by_email: fields.is_password_divided_by_email,
|
||||
zip_encrypt_password: fields.zip_encrypt_password,
|
||||
is_password_divided_by_obj_storage: fields.is_password_divided_by_obj_storage,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { crontab, interval, is_periodic } from '../const'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
|
||||
function getAccountBackupFields() {
|
||||
const recipients_part_one = {
|
||||
@@ -85,9 +85,7 @@ function getAccountBackupFields() {
|
||||
}
|
||||
}
|
||||
return {
|
||||
is_periodic: is_periodic,
|
||||
crontab: crontab,
|
||||
interval: interval,
|
||||
...periodicMeta,
|
||||
is_password_divided_by_email: is_password_divided_by_email,
|
||||
is_password_divided_by_obj_storage: is_password_divided_by_obj_storage,
|
||||
recipients_part_one: recipients_part_one,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { PasswordRule, Select2, TagInput, UpdateToken } from '@/components/Form/FormFields'
|
||||
import { crontab, interval, is_periodic } from '../../accounts/const'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
|
||||
export const getChangeSecretFields = () => {
|
||||
return {
|
||||
@@ -75,9 +75,7 @@ export const getChangeSecretFields = () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
interval,
|
||||
crontab,
|
||||
is_periodic,
|
||||
...periodicMeta,
|
||||
accounts: {
|
||||
label: i18n.t('Accounts'),
|
||||
component: TagInput
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
:table-config="tableConfig"
|
||||
:tree-setting="treeSetting"
|
||||
/>
|
||||
<AccountDiscoverDialog :asset="discoveryDialog.asset" :visible.sync="discoveryDialog.visible" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -20,11 +21,13 @@
|
||||
import AssetTreeTable from '@/components/Apps/AssetTreeTable/index.vue'
|
||||
import DeleteDialog from '@/views/accounts/AccountDiscover/DeleteDialog.vue'
|
||||
import { gatherAccountHeaderActions, gatherAccountTableConfig } from '@/views/accounts/const'
|
||||
import AccountDiscoverDialog from '@/views/assets/Asset/AssetList/components/AccountDiscoverDialog.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AssetTreeTable,
|
||||
DeleteDialog
|
||||
DeleteDialog,
|
||||
AccountDiscoverDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -33,9 +36,16 @@ export default {
|
||||
visible: false,
|
||||
account: {}
|
||||
},
|
||||
discoveryDialog: {
|
||||
asset: '',
|
||||
visible: false
|
||||
},
|
||||
gatherAccounts: [],
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showDefaultMenu: false,
|
||||
showMenu: (node) => {
|
||||
return node.meta.type === 'asset'
|
||||
},
|
||||
showRefresh: true,
|
||||
showSearch: true,
|
||||
showAssets: true,
|
||||
@@ -43,7 +53,20 @@ export default {
|
||||
url: '/api/v1/accounts/gathered-accounts/',
|
||||
nodeUrl: '/api/v1/assets/nodes/',
|
||||
// ?assets=0不显示资产. =1显示资产
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=1'
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=1&asset_amount=0',
|
||||
menu: [
|
||||
{
|
||||
id: 'discover',
|
||||
icon: 'discovery',
|
||||
name: '发现账号',
|
||||
callback: (node) => {
|
||||
console.log('Discovery it: ', node)
|
||||
this.discoveryDialog.asset = node.id
|
||||
this.discoveryDialog.visible = true
|
||||
// this.discoveryDialog.asset = node.data
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
quickSummary: [
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { crontab, interval, is_periodic } from '@/views/accounts/const'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -22,14 +22,12 @@ export default {
|
||||
url: '/api/v1/accounts/gather-account-automations/',
|
||||
hasDetailInMsg: false,
|
||||
fieldsMeta: {
|
||||
...periodicMeta,
|
||||
is_sync_account: {
|
||||
label: this.$t('IsSyncAccountLabel'),
|
||||
helpText: this.$t('IsSyncAccountHelpText')
|
||||
},
|
||||
check_risk: {},
|
||||
is_periodic,
|
||||
crontab,
|
||||
interval,
|
||||
assets: {
|
||||
el: {
|
||||
multiple: true,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<script>
|
||||
import { GenericDetailPage, TabPage } from '@/layout/components'
|
||||
import Detail from './Detail.vue'
|
||||
import TaskExecutionList from './TaskExecutionList.vue'
|
||||
import TaskExecutionList from '../TaskExecutionList.vue'
|
||||
|
||||
export default {
|
||||
name: 'AccountDiscoverTaskDetail',
|
||||
|
||||
@@ -24,8 +24,8 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/accounts/gather-account-executions/',
|
||||
columns: [
|
||||
'automation', 'account_gather_name', 'status', 'trigger', 'date_start',
|
||||
'date_finished', 'actions'
|
||||
'automation', 'account_gather_name', 'status', 'trigger',
|
||||
'date_start', 'date_finished', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
automation: {
|
||||
@@ -77,6 +77,15 @@ export default {
|
||||
callback: function({ row }) {
|
||||
return this.$router.push({ name: 'AccountDiscoverExecutionDetail', params: { id: row.id }})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'report',
|
||||
title: this.$t('Report'),
|
||||
type: 'success',
|
||||
can: this.$hasPerm('accounts.view_gatheraccountsexecution'),
|
||||
callback: function({ row }) {
|
||||
window.open(`/api/v1/accounts/gather-account-executions/${row.id}/report/`)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export default {
|
||||
title: this.$t('ExecutionList'),
|
||||
name: 'AccountDiscoverTaskExecutionList',
|
||||
hidden: !this.$hasPerm('accounts.view_gatheraccountsexecution'),
|
||||
component: () => import('@/views/accounts/AccountDiscover/TaskDetail/TaskExecutionList.vue')
|
||||
component: () => import('@/views/accounts/AccountDiscover/TaskExecutionList.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import { getChangeSecretFields } from '@/views/accounts/AccountChangeSecret/fields'
|
||||
import { AssetSelect, AutomationParams } from '@/components'
|
||||
import { crontab, interval, is_periodic } from '@/views/accounts/const'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
|
||||
export default {
|
||||
name: 'AccountPushCreateUpdate',
|
||||
@@ -47,6 +47,7 @@ export default {
|
||||
[this.$t('Other'), ['is_active', 'comment']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
...periodicMeta,
|
||||
...getChangeSecretFields(),
|
||||
assets: {
|
||||
type: 'assetSelect',
|
||||
@@ -91,9 +92,6 @@ export default {
|
||||
readonly: true
|
||||
}
|
||||
},
|
||||
is_periodic,
|
||||
crontab,
|
||||
interval,
|
||||
params: {
|
||||
component: AutomationParams,
|
||||
label: this.$t('PushParams'),
|
||||
|
||||
@@ -1,49 +1,6 @@
|
||||
import { CronTab } from '@/components'
|
||||
import i18n from '@/i18n/i18n'
|
||||
import InputWithUnit from '@/components/Form/FormFields/InputWithUnit.vue'
|
||||
import store from '@/store'
|
||||
import { toSafeLocalDateStr } from '@/utils/time'
|
||||
import { ActionsFormatter, DiscoverConfirmFormatter } from '@/components/Table/TableFormatters'
|
||||
|
||||
const validatorInterval = (rule, value, callback) => {
|
||||
if (parseInt(value) < 1) {
|
||||
return callback(new Error(i18n.t('EnsureThisValueIsGreaterThanOrEqualTo1')))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
export const crontab = {
|
||||
type: 'cronTab',
|
||||
component: CronTab,
|
||||
label: i18n.t('Crontab'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
helpText: i18n.t('CrontabHelpText'),
|
||||
helpTip: i18n.t('CrontabHelpTip')
|
||||
}
|
||||
|
||||
export const interval = {
|
||||
label: i18n.t('Interval'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
component: InputWithUnit,
|
||||
el: {
|
||||
unit: 'hour'
|
||||
},
|
||||
rules: [
|
||||
{ validator: validatorInterval }
|
||||
]
|
||||
}
|
||||
|
||||
export const is_periodic = {
|
||||
type: 'checkbox',
|
||||
hidden: (formValue) => {
|
||||
return !store.getters.hasValidLicense
|
||||
}
|
||||
}
|
||||
|
||||
export const gatherAccountTableConfig = (vm, url) => {
|
||||
if (!url) {
|
||||
url = '/api/v1/accounts/gathered-accounts/'
|
||||
@@ -218,9 +175,3 @@ export const gatherAccountHeaderActions = (vm) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
crontab: crontab,
|
||||
interval: interval,
|
||||
is_periodic: is_periodic
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,10 @@ export default {
|
||||
category: 'all',
|
||||
treeSetting: {
|
||||
url: '/api/v1/assets/assets/',
|
||||
showMenu: !this.$store.getters.currentOrgIsRoot
|
||||
showMenu: !this.$store.getters.currentOrgIsRoot,
|
||||
showDefaultMenu: true,
|
||||
menu: [
|
||||
]
|
||||
},
|
||||
tableConfig: {
|
||||
url: tableUrl,
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
top="35vh"
|
||||
width="80%"
|
||||
>
|
||||
<ListTable v-bind="config" />
|
||||
<!-- <ListTable v-bind="config" />-->
|
||||
<span v-if="loading" v-loading="loading" class="loading" />
|
||||
<iframe :src="url" frameborder="0" @load="onIframeLoad" />
|
||||
</Dialog>
|
||||
<RemoveAccount
|
||||
v-if="showDeleteAccountDialog"
|
||||
:accounts="gatherAccounts"
|
||||
:visible.sync="showDeleteAccountDialog"
|
||||
/>
|
||||
<!-- <RemoveAccount-->
|
||||
<!-- v-if="showDeleteAccountDialog"-->
|
||||
<!-- :accounts="gatherAccounts"-->
|
||||
<!-- :visible.sync="showDeleteAccountDialog"-->
|
||||
<!-- />-->
|
||||
</div>
|
||||
|
||||
</template>
|
||||
@@ -24,14 +26,10 @@
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog/index.vue'
|
||||
import { gatherAccountHeaderActions, gatherAccountTableConfig } from '@/views/accounts/const'
|
||||
import ListTable from '@/components/Table/ListTable/index.vue'
|
||||
import RemoveAccount from '@/components/Apps/AccountListTable/RemoveAccount.vue'
|
||||
|
||||
export default {
|
||||
name: 'AccountDiscoverDialog',
|
||||
components: {
|
||||
RemoveAccount,
|
||||
ListTable,
|
||||
Dialog
|
||||
},
|
||||
props: {
|
||||
@@ -47,6 +45,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
showDeleteAccountDialog: false,
|
||||
loading: true,
|
||||
gatherAccounts: [],
|
||||
config: {
|
||||
tableConfig: gatherAccountTableConfig(this, `/api/v1/accounts/gathered-accounts/discover/?asset_id=${this.asset}`),
|
||||
@@ -62,6 +61,11 @@ export default {
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
},
|
||||
url: {
|
||||
get() {
|
||||
return `/api/v1/accounts/gathered-accounts/discover/?asset_id=${this.asset}`
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -76,6 +80,22 @@ export default {
|
||||
},
|
||||
beforeMount() {
|
||||
},
|
||||
methods: {}
|
||||
methods: {
|
||||
onIframeLoad() {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
margin-top: 20px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
ref="form"
|
||||
class="form"
|
||||
v-bind="settings"
|
||||
@submitSuccess="handleSubmitSuccess"
|
||||
@performFinished="handlePerformFinished"
|
||||
@submitSuccess="handleSubmitSuccess"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { GenericCreateUpdateForm } from '@/layout/components'
|
||||
import { crontab, interval, is_periodic } from '@/views/accounts/const'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
|
||||
export default {
|
||||
name: 'ResultPanel',
|
||||
@@ -21,7 +21,8 @@ export default {
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
default: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -33,9 +34,7 @@ export default {
|
||||
[this.$t('Timer'), ['is_periodic', 'interval', 'crontab']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
is_periodic,
|
||||
interval,
|
||||
crontab
|
||||
...periodicMeta
|
||||
},
|
||||
defaultButton: false,
|
||||
submitMethod: 'put',
|
||||
@@ -92,6 +91,7 @@ export default {
|
||||
::v-deep .el-form-item.form-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.form {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import { CronTab, Select2 } from '@/components'
|
||||
import { Select2 } from '@/components'
|
||||
import rules from '@/components/Form/DataForm/rules'
|
||||
import SyncInstanceTaskStrategy from './components/SyncInstanceTaskStrategy/index'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -34,6 +35,7 @@ export default {
|
||||
],
|
||||
url: '/api/v1/xpack/cloud/sync-instance-tasks/',
|
||||
fieldsMeta: {
|
||||
...periodicMeta,
|
||||
account: {
|
||||
label: this.$t('xpack.Cloud.Account'),
|
||||
on: {
|
||||
@@ -86,24 +88,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
is_periodic: {
|
||||
type: 'checkbox'
|
||||
},
|
||||
crontab: {
|
||||
component: CronTab,
|
||||
label: this.$t('xpack.RegularlyPerform'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
helpText: this.$t('xpack.HelpText.CrontabOfCreateUpdatePage')
|
||||
},
|
||||
interval: {
|
||||
label: this.$t('xpack.CyclePerform'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
helpText: this.$t('xpack.HelpText.IntervalOfCreateUpdatePage')
|
||||
},
|
||||
strategy: {
|
||||
label: this.$t('common.Strategy'),
|
||||
component: SyncInstanceTaskStrategy,
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import { getChangeSecretFields } from '@/views/accounts/AccountChangeSecret/fields'
|
||||
import { AssetSelect } from '@/components'
|
||||
import { crontab, interval, is_periodic } from '@/views/accounts/const'
|
||||
import { periodicMeta } from '@/components/const'
|
||||
import i18n from '@/i18n/i18n'
|
||||
|
||||
export default {
|
||||
@@ -18,18 +17,11 @@ export default {
|
||||
return {
|
||||
nodeIds: [],
|
||||
assetIds: [],
|
||||
isAssetType: '',
|
||||
initial: {
|
||||
is_periodic: false,
|
||||
password_rules: {
|
||||
length: 30
|
||||
},
|
||||
interval: 24,
|
||||
secret_type: 'password',
|
||||
secret_strategy: 'specific'
|
||||
interval: 24
|
||||
},
|
||||
url: '/api/v1/accounts/check-account-automations/',
|
||||
encryptedFields: ['secret'],
|
||||
fields: [
|
||||
[this.$t('Basic'), ['name']],
|
||||
[this.$t('Asset'), ['assets', 'nodes']],
|
||||
@@ -38,7 +30,6 @@ export default {
|
||||
[this.$t('Other'), ['is_active', 'comment']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
...getChangeSecretFields(),
|
||||
assets: {
|
||||
type: 'assetSelect',
|
||||
component: AssetSelect,
|
||||
@@ -100,33 +91,10 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
username: {
|
||||
hidden: (formValue) => formValue['dynamic_username']
|
||||
},
|
||||
ssh_key_change_strategy: {
|
||||
hidden: (formValue) => formValue['action'] !== 'create_and_push' ||
|
||||
formValue['secret_type'] !== 'ssh_key'
|
||||
},
|
||||
triggers: {
|
||||
el: {
|
||||
readonly: true
|
||||
}
|
||||
},
|
||||
is_periodic,
|
||||
crontab,
|
||||
interval
|
||||
...periodicMeta
|
||||
},
|
||||
createSuccessNextRoute: { name: 'AccountCheckList' },
|
||||
updateSuccessNextRoute: { name: 'AccountCheckList' },
|
||||
afterGetRemoteMeta: this.handleAfterGetRemoteMeta,
|
||||
cleanFormValue(data) {
|
||||
const secretType = data.secret_type || ''
|
||||
if (secretType !== 'password') {
|
||||
data.secret = data[secretType]
|
||||
delete data[secretType]
|
||||
}
|
||||
return data
|
||||
}
|
||||
updateSuccessNextRoute: { name: 'AccountCheckList' }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -134,20 +102,7 @@ export default {
|
||||
return this.$route.path.indexOf('/update') > -1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
nodeIds: {
|
||||
handler(val) {
|
||||
this.fieldsMeta.params.el.nodes = val
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
assetIds: {
|
||||
handler(val) {
|
||||
this.fieldsMeta.params.el.assets = val
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
mounted() {
|
||||
if (!this.$store.getters.hasValidLicense) {
|
||||
delete this.fields[3]
|
||||
@@ -156,15 +111,6 @@ export default {
|
||||
methods: {
|
||||
hasType(type) {
|
||||
return this.isAssetType.indexOf(type) > -1
|
||||
},
|
||||
handleAfterGetRemoteMeta(meta) {
|
||||
const needSetOptionFields = [
|
||||
'secret_type', 'secret_strategy', 'ssh_key_change_strategy'
|
||||
]
|
||||
for (const i of needSetOptionFields) {
|
||||
const field = this.fieldsMeta[i] || {}
|
||||
field.options = meta[i]?.choices || []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
return {
|
||||
gatherAccounts: [],
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showMenu: true,
|
||||
showRefresh: true,
|
||||
showSearch: true,
|
||||
showAssets: true,
|
||||
@@ -31,7 +31,15 @@ export default {
|
||||
url: '/api/v1/accounts/account-risks/',
|
||||
nodeUrl: '/api/v1/assets/nodes/',
|
||||
// ?assets=0不显示资产. =1显示资产
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=1&asset_amount=0'
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=1&asset_amount=0',
|
||||
menu: [
|
||||
{
|
||||
id: 'check',
|
||||
name: this.$t('Check'),
|
||||
icon: 'scan',
|
||||
callback: () => {}
|
||||
}
|
||||
]
|
||||
},
|
||||
quickFilters: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user