mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-29 21:28:52 +00:00
10
README.md
10
README.md
@@ -46,12 +46,4 @@ server {
|
||||
|
||||
|
||||
## License & Copyright
|
||||
Copyright (c) 2014-2021 飞致云 FIT2CLOUD, All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
https://github.com/jumpserver/lina/blob/dev/LICENSE
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
|
||||
Be consistent with [jumpserver](https://github.com/jumpserver/jumpserver)
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
<el-form-item :label="this.$t('assets.SSHKey')">
|
||||
<input type="file" @change="onPrivateKeyLoaded">
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Passphrase')">
|
||||
<el-input v-model="authInfo.passphrase" type="password" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -42,7 +45,8 @@ export default {
|
||||
return {
|
||||
authInfo: {
|
||||
password: '',
|
||||
private_key: ''
|
||||
private_key: '',
|
||||
passphrase: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -54,6 +58,7 @@ export default {
|
||||
}
|
||||
if (this.authInfo.private_key !== '') {
|
||||
data.private_key = this.authInfo.private_key
|
||||
data.passphrase = this.authInfo.passphrase
|
||||
}
|
||||
this.$axios.patch(
|
||||
`/api/v1/assets/accounts/${this.account.id}/`,
|
||||
|
||||
@@ -18,6 +18,9 @@ export class FormFieldGenerator {
|
||||
})
|
||||
}
|
||||
break
|
||||
case 'multiple choice':
|
||||
field.el.choices = fieldRemoteMeta['choices']
|
||||
break
|
||||
case 'datetime':
|
||||
type = 'date-picker'
|
||||
field.el = {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<template v-for="option in action.dropdown">
|
||||
<div v-if="option.group" :key="'group:'+option.name" class="dropdown-menu-title">
|
||||
<div v-if="option.group" :key="'group:'+option.name" class="dropdown-menu-title" style="width:130px">
|
||||
{{ option.group }}
|
||||
</div>
|
||||
<el-dropdown-item
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<input type="file" @change="Onchange">
|
||||
<input ref="upLoadFile" type="file" style="display: none" @change="Onchange">
|
||||
<el-button size="mini" @click.native.stop="onUpLoad">
|
||||
{{ this.$t('common.SelectFile') }}
|
||||
</el-button>
|
||||
<span>{{ fileName }}</span>
|
||||
<div v-if="tip !== ''">{{ tip }}</div>
|
||||
<input v-model="value" type="text" hidden v-on="$listeners">
|
||||
<div>
|
||||
@@ -23,6 +27,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fileName: '',
|
||||
initial: this.value,
|
||||
preview: this.value
|
||||
}
|
||||
@@ -34,16 +39,21 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onUpLoad() {
|
||||
this.$refs.upLoadFile.click()
|
||||
},
|
||||
onInput(val) {
|
||||
this.$emit('input', val)
|
||||
},
|
||||
Onchange(e) {
|
||||
if (e.target.files[0] === undefined) {
|
||||
const upLoadFile = e.target.files[0]
|
||||
if (upLoadFile === undefined) {
|
||||
this.$emit('input', this.initial)
|
||||
return
|
||||
}
|
||||
this.$emit('fileChange', e.target.files[0])
|
||||
this.$emit('input', this.getObjectURL(e.target.files[0]))
|
||||
this.fileName = upLoadFile?.name || ''
|
||||
this.$emit('fileChange', upLoadFile)
|
||||
this.$emit('input', this.getObjectURL(upLoadFile))
|
||||
},
|
||||
getObjectURL(file) {
|
||||
let url = null
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"vmware_client":"Vmware Client",
|
||||
"custom":"Custom",
|
||||
"mysql": "MySQL",
|
||||
"redis": "Redis",
|
||||
"oracle": "Oracle",
|
||||
"postgresql": "PostgreSQL",
|
||||
"mariadb": "MariaDB",
|
||||
@@ -88,7 +89,9 @@
|
||||
"cluster": "集群",
|
||||
"kubernetes":"Kubernetes",
|
||||
"clusterHelpTextMessage": "例如:https://172.16.8.8:8443",
|
||||
"DBInfo": "数据库信息"
|
||||
"DBInfo": "数据库信息",
|
||||
"RDBProtocol": "关系型数据库协议",
|
||||
"NoSQLProtocol": "非关系型数据库协议"
|
||||
},
|
||||
"assets": {
|
||||
"AppList": "应用列表",
|
||||
@@ -168,6 +171,7 @@
|
||||
"Other": "其它",
|
||||
"Hardware": "硬件信息",
|
||||
"Password": "密码",
|
||||
"Passphrase": "密钥密码",
|
||||
"PasswordWithoutSpecialCharHelpText": "不能包含特殊字符",
|
||||
"Pending": "等待",
|
||||
"Platform": "系统平台",
|
||||
@@ -228,6 +232,8 @@
|
||||
"ipDomain": "IP(域名)",
|
||||
"HostProtocol": "主机协议",
|
||||
"DatabaseProtocol": "数据库协议",
|
||||
"RDBProtocol": "关系型数据库协议",
|
||||
"NoSQLProtocol": "非关系型数据库协议",
|
||||
"OtherProtocol": "其它协议",
|
||||
"PasswordOrToken": "密码 / 令牌"
|
||||
},
|
||||
@@ -296,6 +302,7 @@
|
||||
"Close": "关闭",
|
||||
"Command filter": "命令过滤器",
|
||||
"Comment": "备注",
|
||||
"Number": "编号",
|
||||
"Confirm": "确认",
|
||||
"Create": "创建",
|
||||
"CreatedBy": "创建者",
|
||||
@@ -784,6 +791,7 @@
|
||||
"accountName": "账户名称",
|
||||
"active": "激活中",
|
||||
"alive": "在线",
|
||||
"noAlive": "离线",
|
||||
"asset": "资产",
|
||||
"target": "目标",
|
||||
"bucket": "桶名称",
|
||||
@@ -1302,6 +1310,10 @@
|
||||
"Name": "名称",
|
||||
"NodeAmount": "节点数量",
|
||||
"PasswordLength": "密码长度",
|
||||
"ChangePassword": "更改密码",
|
||||
"ModifySSHKey": "修改 SSH Key",
|
||||
"Addressee": "收件人",
|
||||
"OnlyMailSend": "当前只支持邮件发送",
|
||||
"PasswordStrategy": "密码策略",
|
||||
"SecretKeyStrategy": "密钥策略",
|
||||
"RegularlyPerform": "定期执行",
|
||||
@@ -1314,6 +1326,15 @@
|
||||
"TimerPeriod": "定时执行周期",
|
||||
"Username": "用户名"
|
||||
},
|
||||
"AccountBackupPlan": {
|
||||
"AccountBackupPlan": "账号备份",
|
||||
"AccountBackupPlanCreate": "创建账号备份",
|
||||
"AccountBackupPlanUpdate": "更新账号备份",
|
||||
"ExecutionDetail": "执行详情",
|
||||
"MailRecipient": "邮件收件人",
|
||||
"IsSuccess": "是否成功",
|
||||
"Reason": "原因"
|
||||
},
|
||||
"Cloud": {
|
||||
"ServerAccountKey": "服务账号密钥",
|
||||
"IPNetworkSegment": "IP网段",
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"vmware_client":"Vmware Client",
|
||||
"custom":"Custom",
|
||||
"mysql": "MySQL",
|
||||
"redis": "Redis",
|
||||
"oracle": "Oracle",
|
||||
"postgresql": "PostgreSQL",
|
||||
"mariadb": "MariaDB",
|
||||
@@ -83,7 +84,9 @@
|
||||
"cluster": "Cluster",
|
||||
"kubernetes":"Kubernetes",
|
||||
"clusterHelpTextMessage": "Tips: https://172.16.8.8:8443",
|
||||
"DBInfo": "Database Info"
|
||||
"DBInfo": "Database Info",
|
||||
"RDBProtocol": "RDS Protocol",
|
||||
"NoSQLProtocol": "NoSQL Protocol"
|
||||
},
|
||||
"assets": {
|
||||
"AppList": "Application list",
|
||||
@@ -165,6 +168,7 @@
|
||||
"Os": "Os",
|
||||
"Other": "Other",
|
||||
"Password": "Password",
|
||||
"Passphrase": "Passphrase",
|
||||
"PasswordWithoutSpecialCharHelpText": "Password can't has special chars ",
|
||||
"Pending": "Pending",
|
||||
"Platform": "Platform",
|
||||
@@ -222,6 +226,8 @@
|
||||
"ipDomain": "IP(Domain)",
|
||||
"HostProtocol": "Host Protocol",
|
||||
"DatabaseProtocol": "Database Protocol",
|
||||
"RDBProtocol": "RDS Protocol",
|
||||
"NoSQLProtocol": "NoSQL Protocol",
|
||||
"OtherProtocol": "Other Protocol",
|
||||
"PasswordOrToken": "Password / Token"
|
||||
},
|
||||
@@ -283,6 +289,7 @@
|
||||
"Close": "Close",
|
||||
"Command filter": "Command filter",
|
||||
"Comment": "Comment",
|
||||
"Number": "Number",
|
||||
"Confirm": "Confirm",
|
||||
"Create": "Create",
|
||||
"CreatedBy": "Created by",
|
||||
@@ -765,6 +772,7 @@
|
||||
"accountName": "Account name",
|
||||
"active": "active",
|
||||
"alive": "alive",
|
||||
"noAlive": "no alive",
|
||||
"asset": "Asset",
|
||||
"target": "Target",
|
||||
"bucket": "Bucket",
|
||||
@@ -1259,6 +1267,10 @@
|
||||
"Name": "Name",
|
||||
"NodeAmount": "Node",
|
||||
"PasswordLength": "Password length",
|
||||
"ChangePassword": "Change password",
|
||||
"ModifySSHKey": "Modify SSH Key",
|
||||
"Addressee": "Addressee",
|
||||
"OnlyMailSend": "Currently only mail sending is supported",
|
||||
"PasswordStrategy": "Password strategy",
|
||||
"SecretKeyStrategy": "Secret key strategy",
|
||||
"RegularlyPerform": "Regularly perform",
|
||||
@@ -1271,6 +1283,15 @@
|
||||
"TimerPeriod": "Timer period",
|
||||
"Username": "Username"
|
||||
},
|
||||
"AccountBackupPlan": {
|
||||
"AccountBackupPlan": "Account backup plan",
|
||||
"AccountBackupPlanreate": "Account backup plan",
|
||||
"AccountBackupPlanUpdate": "Account backup plan",
|
||||
"ExecutionDetail": "Execution detail",
|
||||
"MailRecipient": "Mail recipient",
|
||||
"IsSuccess": "Is success",
|
||||
"Reason": "Reason"
|
||||
},
|
||||
"Cloud": {
|
||||
"ServerAccountKey": "Server Account Key",
|
||||
"IPNetworkSegment": "Ip Network Segment",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Version <strong> dev </strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv2. </span>
|
||||
</div>
|
||||
<div v-if="!publicSettings.XPACK_LICENSE_IS_VALID" style="padding-left:20px;">
|
||||
<strong>Copyright</strong> FIT2CLOUD 飞致云 © 2014-2021
|
||||
<strong>Copyright</strong> FIT2CLOUD 飞致云 © 2014-{{ curYear }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -12,6 +12,11 @@
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'Footer',
|
||||
data() {
|
||||
return {
|
||||
curYear: this.$moment().year() || ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar',
|
||||
|
||||
@@ -161,5 +161,54 @@ export default [
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'backup',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('xpack.AccountBackupPlan.AccountBackupPlan') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/accounts/AccountBackupPlan/index.vue'),
|
||||
name: 'AccountBackupPlanIndex',
|
||||
meta: { title: i18n.t('xpack.AccountBackupPlan.AccountBackupPlan'), activeMenu: '/accounts/backup' }
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/accounts/AccountBackupPlan/AccountBackupPlanList.vue'),
|
||||
name: 'AccountBackupPlanList',
|
||||
meta: { title: i18n.t('xpack.AccountBackupPlan.AccountBackupPlan'), activeMenu: '/accounts/backup' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: () => import('@/views/accounts/AccountBackupPlan/AccountBackupPlanCreateUpdate.vue'),
|
||||
name: 'AccountBackupPlanCreate',
|
||||
meta: { title: i18n.t('xpack.AccountBackupPlan.AccountBackupPlanCreate'), activeMenu: '/accounts/backup', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
component: () => import('@/views/accounts/AccountBackupPlan/AccountBackupPlanCreateUpdate.vue'),
|
||||
name: 'AccountBackupPlanUpdate',
|
||||
meta: { title: i18n.t('xpack.AccountBackupPlan.AccountBackupPlanUpdate'), activeMenu: '/accounts/backup', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: () => import('@/views/accounts/AccountBackupPlan/AccountBackupPlanDetail/index.vue'),
|
||||
name: 'AccountBackupPlanDetail',
|
||||
meta: { title: i18n.t('xpack.AccountBackupPlan.AccountBackupPlan'), activeMenu: '/accounts/backup' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan-execution/:id',
|
||||
component: () => import('@/views/accounts/AccountBackupPlan/AccountBackupPlanDetail/AccountBackupPlanExecution/AccountBackupPlanExecutionDetail/index.vue'),
|
||||
name: 'AccountBackupPlanExecutionDetail',
|
||||
meta: { title: i18n.t('xpack.AccountBackupPlan.ExecutionDetail'), activeMenu: '/accounts/backup' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<GenericCreateUpdatePage v-bind="$data" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import getFields from '@/views/accounts/AccountBackupPlan/fields'
|
||||
import FormTypeField from './components/FormTypeField'
|
||||
|
||||
export default {
|
||||
name: 'AccountBackupPlanUpdate',
|
||||
components: {
|
||||
GenericCreateUpdatePage
|
||||
},
|
||||
data() {
|
||||
const fields = getFields.bind(this)()
|
||||
return {
|
||||
url: '/api/v1/assets/backup/',
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'types']],
|
||||
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
|
||||
[this.$t('common.Other'), ['recipients', 'comment']]
|
||||
],
|
||||
initial: {
|
||||
is_periodic: true,
|
||||
interval: 24,
|
||||
types: ['all', 'asset', 'application']
|
||||
},
|
||||
fieldsMeta: {
|
||||
is_periodic: fields.is_periodic,
|
||||
crontab: fields.crontab,
|
||||
interval: fields.interval,
|
||||
recipients: fields.recipients,
|
||||
types: {
|
||||
label: this.$t('perms.Actions'),
|
||||
component: FormTypeField
|
||||
}
|
||||
},
|
||||
createSuccessNextRoute: { name: 'AccountBackupPlanIndex' },
|
||||
updateSuccessNextRoute: { name: 'AccountBackupPlanIndex' },
|
||||
cleanFormValue(data) {
|
||||
if (data['interval'] === '') {
|
||||
delete data['interval']
|
||||
}
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailItems" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DetailCard from '@/components/DetailCard'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
|
||||
export default {
|
||||
name: 'AccountBackupPlanExecutionInfo',
|
||||
components: {
|
||||
DetailCard
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
detailItems() {
|
||||
return [
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.TimeDelta'),
|
||||
value: this.object.timedelta.toFixed(2) + 's'
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.DateStart'),
|
||||
value: toSafeLocalDateStr(this.object.date_start)
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.AccountBackupPlan.IsSuccess'),
|
||||
value: this.object.is_success
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.AccountBackupPlan.Reason'),
|
||||
value: this.object.reason
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.MailRecipient'),
|
||||
value: this.object.recipients ? this.object.recipients.map(
|
||||
i => `${i[0]}` + `${i[1] ? ': ' + this.$t('xpack.ChangeAuthPlan.ContainAttachment') : ''}`).join(', ') : ''
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<GenericDetailPage :object.sync="execution" :active-menu.sync="config.activeMenu" v-bind="config" v-on="$listeners">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" :object="execution" />
|
||||
</keep-alive>
|
||||
</GenericDetailPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericDetailPage } from '@/layout/components'
|
||||
import AccountBackupPlanExecutionInfo from './AccountBackupPlanExecutionInfo'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GenericDetailPage,
|
||||
AccountBackupPlanExecutionInfo
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
execution: { id: '' },
|
||||
config: {
|
||||
activeMenu: 'AccountBackupPlanExecutionInfo',
|
||||
actions: {
|
||||
detailApiUrl: `/api/v1/assets/backup-execution/${this.$route.params.id}/`,
|
||||
hasUpdate: false,
|
||||
hasDelete: false
|
||||
},
|
||||
submenu: [
|
||||
{
|
||||
title: this.$t('common.BasicInfo'),
|
||||
name: 'AccountBackupPlanExecutionInfo'
|
||||
}
|
||||
],
|
||||
getTitle: this.getExecutionTitle
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getExecutionTitle() {
|
||||
return `${this.$route.meta.title}: ${this.execution.id}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
|
||||
export default {
|
||||
name: 'AccountBackupPlanExecution',
|
||||
components: {
|
||||
GenericListTable
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: `/api/v1/assets/backup-execution/?plan_id=${this.object.id}`,
|
||||
columns: [
|
||||
'timedelta', 'trigger_display', 'date_start', 'is_success', 'reason', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
timedelta: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.TimeDelta'),
|
||||
width: '90px',
|
||||
formatter: function(row) {
|
||||
return row.timedelta.toFixed(2) + 's'
|
||||
}
|
||||
},
|
||||
date_start: {
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
hasUpdate: false,
|
||||
hasClone: false,
|
||||
extraActions: [
|
||||
{
|
||||
name: 'log',
|
||||
type: 'primary',
|
||||
title: this.$t('xpack.ChangeAuthPlan.Log'),
|
||||
callback: function({ row }) {
|
||||
window.open(`/#/ops/celery/task/${row.id}/log/`, '_blank', 'toolbar=yes, width=900, height=600')
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'detail',
|
||||
title: this.$t('xpack.ChangeAuthPlan.Detail'),
|
||||
type: 'info',
|
||||
callback: function({ row }) {
|
||||
return this.$router.push({ name: 'AccountBackupPlanExecutionDetail', params: { id: row.id }})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasSearch: true,
|
||||
hasRefresh: true,
|
||||
hasRightActions: true,
|
||||
hasLeftActions: true,
|
||||
hasMoreActions: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasCreate: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailItems" />
|
||||
</el-col>
|
||||
<el-col :md="10" :sm="24">
|
||||
<QuickActions :actions="quickActions" type="primary" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DetailCard, QuickActions } from '@/components'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
|
||||
export default {
|
||||
name: 'AccountBackupPlanInfo',
|
||||
components: {
|
||||
DetailCard,
|
||||
QuickActions
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
quickActions: [
|
||||
{
|
||||
title: this.$t('xpack.ChangeAuthPlan.ManualExecutePlan'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$t('xpack.ChangeAuthPlan.Execute')
|
||||
},
|
||||
callbacks: {
|
||||
click: function() {
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/backup-execution/`,
|
||||
{ plan: this.object.id }
|
||||
).then(res => {
|
||||
window.open(`/#/ops/celery/task/${res.task}/log/`, '_blank', 'toolbar=yes, width=900, height=600')
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
detailItems() {
|
||||
return [
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.Name'),
|
||||
value: this.object.name
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.RegularlyPerform'),
|
||||
value: this.object.crontab,
|
||||
formatter: (item, val) => {
|
||||
return <span>{this.object.is_periodic ? val : ''}</span>
|
||||
}
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.CyclePerform'),
|
||||
value: this.object.interval,
|
||||
formatter: (item, val) => {
|
||||
return <span>{this.object.is_periodic ? val : ''}</span>
|
||||
}
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.DateJoined'),
|
||||
value: toSafeLocalDateStr(this.object.date_created)
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.DateUpdated'),
|
||||
value: toSafeLocalDateStr(this.object.date_updated)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Comment'),
|
||||
value: this.object.comment
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<GenericDetailPage :object.sync="plan" :active-menu.sync="config.activeMenu" v-bind="config">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" :object="plan" />
|
||||
</keep-alive>
|
||||
</GenericDetailPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericDetailPage } from '@/layout/components'
|
||||
import AccountBackupPlanInfo from './AccountBackupPlanInfo'
|
||||
import AccountBackupPlanExecutionList from './AccountBackupPlanExecution/AccountBackupPlanExecutionList'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GenericDetailPage,
|
||||
AccountBackupPlanInfo,
|
||||
AccountBackupPlanExecutionList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
plan: { name: '', comment: '' },
|
||||
config: {
|
||||
activeMenu: 'AccountBackupPlanInfo',
|
||||
submenu: [
|
||||
{
|
||||
title: this.$t('common.BasicInfo'),
|
||||
name: 'AccountBackupPlanInfo'
|
||||
},
|
||||
{
|
||||
title: this.$t('xpack.ChangeAuthPlan.ExecutionList'),
|
||||
name: 'AccountBackupPlanExecutionList'
|
||||
}
|
||||
],
|
||||
actions: {
|
||||
detailApiUrl: `/api/v1/assets/backup/${this.$route.params.id}/`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericListTable } from '@/layout/components'
|
||||
import { DetailFormatter } from '@/components/TableFormatters'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
|
||||
export default {
|
||||
name: 'AccountBackupPlanList',
|
||||
components: {
|
||||
GenericListTable
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/backup/',
|
||||
columns: [
|
||||
'name', 'is_periodic', 'periodic_display', 'org_name', 'comment', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: ['name', 'org_name', 'is_periodic', 'periodic_display', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AccountBackupPlanDetail'
|
||||
}
|
||||
},
|
||||
is_periodic: {
|
||||
label: vm.$t('xpack.ChangeAuthPlan.Timer'),
|
||||
formatterArgs: {
|
||||
showFalse: false
|
||||
},
|
||||
width: '80px'
|
||||
},
|
||||
periodic_display: {
|
||||
label: vm.$t('xpack.ChangeAuthPlan.TimerPeriod'),
|
||||
showOverflowTooltip: true,
|
||||
width: '150px'
|
||||
},
|
||||
comment: {
|
||||
width: '90px'
|
||||
},
|
||||
actions: {
|
||||
width: '164px',
|
||||
formatterArgs: {
|
||||
onClone: ({ row }) => {
|
||||
vm.$router.push({ name: 'AccountBackupPlanCreate', query: { clone_from: row.id }})
|
||||
},
|
||||
onUpdate: ({ row }) => {
|
||||
vm.$router.push({ name: 'AccountBackupPlanUpdate', params: { id: row.id }})
|
||||
},
|
||||
extraActions: [
|
||||
{
|
||||
title: vm.$t('xpack.Execute'),
|
||||
name: 'execute',
|
||||
type: 'info',
|
||||
callback: function({ row }) {
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/backup-execution/`,
|
||||
{ plan: row.id }
|
||||
).then(res => {
|
||||
openTaskPage(res['task'])
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasRefresh: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasMoreActions: false,
|
||||
createRoute: () => {
|
||||
return {
|
||||
name: 'AccountBackupPlanCreate'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<el-tree
|
||||
:data="iData"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
:default-expand-all="false"
|
||||
:default-checked-keys="value"
|
||||
:props="defaultProps"
|
||||
v-bind="$attrs"
|
||||
@check="handleCheckChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FormTypeField',
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
choices: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'label'
|
||||
},
|
||||
fullChoicesTreeNodes: [
|
||||
{
|
||||
id: 'all',
|
||||
label: this.$t('perms.all'),
|
||||
children: [
|
||||
{
|
||||
id: 'asset',
|
||||
label: this.$t('assets.Assets')
|
||||
},
|
||||
{
|
||||
id: 'application',
|
||||
label: this.$t('assets.Applications')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
choicesIDs() {
|
||||
return this.choices.map((v) => v.value)
|
||||
},
|
||||
iData() {
|
||||
this.$log.debug('choices: ', this.choicesIDs)
|
||||
const fullTreeNodes = _.cloneDeep(this.fullChoicesTreeNodes)
|
||||
const treeNodes = this.trimChoicesTreeNodes(fullTreeNodes)
|
||||
this.$log.debug('choicesTreeNodes: ', treeNodes)
|
||||
return treeNodes
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
trimChoicesTreeNodes(treeNodes) {
|
||||
const newTreeNodes = []
|
||||
for (const treeNode of treeNodes) {
|
||||
if (!this.choicesIDs.includes(treeNode.id)) {
|
||||
continue
|
||||
}
|
||||
let children = treeNode.children || []
|
||||
if (children.length !== 0) {
|
||||
children = this.trimChoicesTreeNodes(children)
|
||||
treeNode.children = children
|
||||
}
|
||||
newTreeNodes.push(treeNode)
|
||||
}
|
||||
return newTreeNodes
|
||||
},
|
||||
handleCheckChange(data, obj) {
|
||||
const checkedKeys = obj.checkedKeys
|
||||
if (checkedKeys.length !== 0) {
|
||||
checkedKeys.push('connect')
|
||||
}
|
||||
this.$emit('input', checkedKeys)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
57
src/views/accounts/AccountBackupPlan/fields.js
Normal file
57
src/views/accounts/AccountBackupPlan/fields.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { CronTab } from '@/components'
|
||||
|
||||
var validatorInterval = (rule, value, callback) => {
|
||||
if (parseInt(value) < 1) {
|
||||
return callback(new Error(i18n.t('xpack.ChangeAuthPlan.validatorMessage.EnsureThisValueIsGreaterThanOrEqualTo1')))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
function getFields() {
|
||||
const recipients = {
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
url: '/api/v1/users/users/?fields_size=mini',
|
||||
transformOption: (item) => {
|
||||
return { label: item.name + '(' + item.username + ')', value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const is_periodic = {
|
||||
type: 'switch'
|
||||
}
|
||||
|
||||
const crontab = {
|
||||
type: 'cronTab',
|
||||
component: CronTab,
|
||||
label: i18n.t('xpack.RegularlyPerform'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
helpText: i18n.t('xpack.HelpText.CrontabOfCreateUpdatePage')
|
||||
}
|
||||
|
||||
const interval = {
|
||||
label: i18n.t('xpack.CyclePerform'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_periodic === false
|
||||
},
|
||||
helpText: i18n.t('xpack.HelpText.IntervalOfCreateUpdatePage'),
|
||||
rules: [
|
||||
{ validator: validatorInterval }
|
||||
]
|
||||
}
|
||||
|
||||
return {
|
||||
is_periodic: is_periodic,
|
||||
crontab: crontab,
|
||||
interval: interval,
|
||||
recipients: recipients
|
||||
}
|
||||
}
|
||||
|
||||
export default getFields
|
||||
36
src/views/accounts/AccountBackupPlan/index.vue
Normal file
36
src/views/accounts/AccountBackupPlan/index.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" />
|
||||
</keep-alive>
|
||||
</TabPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TabPage } from '@/layout/components'
|
||||
import AccountBackupPlanList from './AccountBackupPlanList'
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
TabPage,
|
||||
AccountBackupPlanList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
activeMenu: 'AccountBackupPlanList',
|
||||
submenu: [
|
||||
{
|
||||
title: this.$t('xpack.AccountBackupPlan.AccountBackupPlan'),
|
||||
name: 'AccountBackupPlanList'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -19,7 +19,7 @@ export default {
|
||||
[this.$t('common.Basic'), ['name']],
|
||||
[this.$t('xpack.Asset'), ['username', 'assets', 'nodes']],
|
||||
[this.$t('xpack.ChangeAuthPlan.PasswordStrategy'), ['is_password', 'password_strategy', 'password', 'password_rules']],
|
||||
[this.$t('xpack.ChangeAuthPlan.SecretKeyStrategy'), ['is_ssh_key', 'ssh_key_strategy', 'private_key']],
|
||||
[this.$t('xpack.ChangeAuthPlan.SecretKeyStrategy'), ['is_ssh_key', 'ssh_key_strategy', 'private_key', 'passphrase']],
|
||||
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
|
||||
[this.$t('common.Other'), ['recipients', 'comment']]
|
||||
],
|
||||
@@ -38,6 +38,7 @@ export default {
|
||||
username: fields.username,
|
||||
assets: fields.assets,
|
||||
password: fields.password,
|
||||
passphrase: fields.passphrase,
|
||||
password_rules: fields.asset_password_rules,
|
||||
private_key: fields.private_key,
|
||||
nodes: fields.nodes,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { AssetSelect, CronTab } from '@/components'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
import { AssetSelect, CronTab, UploadKey } from '@/components'
|
||||
import { Select2 } from '@/components/FormFields/Select2'
|
||||
import { Required } from '@/components/DataForm/rules'
|
||||
|
||||
var validatorInterval = (rule, value, callback) => {
|
||||
@@ -103,6 +103,12 @@ function getFields() {
|
||||
]
|
||||
}
|
||||
|
||||
const passphrase = {
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_ssh_key === false
|
||||
}
|
||||
}
|
||||
|
||||
const asset_password_rules = {
|
||||
type: 'group',
|
||||
items: generatePasswordRulesItemsFields('asset')
|
||||
@@ -114,11 +120,7 @@ function getFields() {
|
||||
}
|
||||
|
||||
const private_key = {
|
||||
el: {
|
||||
type: 'textarea',
|
||||
placeholder: '-----BEGIN OPENSSH PRIVATE KEY-----',
|
||||
autosize: { minRows: 3 }
|
||||
},
|
||||
component: UploadKey,
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_ssh_key === false
|
||||
},
|
||||
@@ -128,6 +130,8 @@ function getFields() {
|
||||
}
|
||||
|
||||
const recipients = {
|
||||
label: i18n.t('xpack.ChangeAuthPlan.Addressee'),
|
||||
helpText: i18n.t('xpack.ChangeAuthPlan.OnlyMailSend'),
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
@@ -153,10 +157,12 @@ function getFields() {
|
||||
}
|
||||
|
||||
const is_password = {
|
||||
label: i18n.t('xpack.ChangeAuthPlan.ChangePassword'),
|
||||
type: 'switch'
|
||||
}
|
||||
|
||||
const is_ssh_key = {
|
||||
label: i18n.t('xpack.ChangeAuthPlan.ModifySSHKey'),
|
||||
type: 'switch'
|
||||
}
|
||||
|
||||
@@ -225,6 +231,7 @@ function getFields() {
|
||||
password_strategy: password_strategy,
|
||||
ssh_key_strategy: ssh_key_strategy,
|
||||
private_key: private_key,
|
||||
passphrase: passphrase,
|
||||
asset_password_rules: asset_password_rules,
|
||||
database_password_rules: database_password_rules,
|
||||
nodes: nodes,
|
||||
|
||||
@@ -11,6 +11,41 @@ export default {
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
const appType = [
|
||||
{
|
||||
name: 'mysql',
|
||||
title: 'MySQL',
|
||||
has: true,
|
||||
group: this.$t('assets.RDBProtocol')
|
||||
},
|
||||
{
|
||||
name: 'postgresql',
|
||||
title: 'PostgreSQL',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'mariadb',
|
||||
title: 'MariaDB',
|
||||
type: 'primary',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'oracle',
|
||||
title: 'Oracle',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'sqlserver',
|
||||
title: 'SQLServer',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'redis',
|
||||
title: 'Redis',
|
||||
has: true,
|
||||
group: this.$t('assets.NoSQLProtocol')
|
||||
}
|
||||
]
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/applications/?category=db',
|
||||
@@ -24,8 +59,7 @@ export default {
|
||||
},
|
||||
columnsMeta: {
|
||||
type_display: {
|
||||
label: this.$t('applications.type'),
|
||||
width: '120px'
|
||||
label: this.$t('applications.type')
|
||||
},
|
||||
'attrs.host': {
|
||||
label: this.$t('applications.host'),
|
||||
@@ -69,43 +103,37 @@ export default {
|
||||
hasBulkDelete: true,
|
||||
createRoute: 'DatabaseAppCreate',
|
||||
searchConfig: {
|
||||
exclude: ['category', 'type']
|
||||
exclude: ['category', 'type'],
|
||||
options: [
|
||||
{
|
||||
value: 'type',
|
||||
label: this.$t('applications.type'),
|
||||
children: this.getAppType(appType)
|
||||
}
|
||||
]
|
||||
},
|
||||
moreCreates: {
|
||||
callback: (item) => {
|
||||
vm.$router.push({ name: 'DatabaseAppCreate', query: { type: item.name.toLowerCase() }})
|
||||
},
|
||||
dropdown: [
|
||||
{
|
||||
name: 'MySQL',
|
||||
title: 'MySQL',
|
||||
has: true
|
||||
},
|
||||
{
|
||||
name: 'PostgreSQL',
|
||||
title: 'PostgreSQL',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'MariaDB',
|
||||
title: 'MariaDB',
|
||||
type: 'primary',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'Oracle',
|
||||
title: 'Oracle',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'SQLServer',
|
||||
title: 'SQLServer',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
}
|
||||
]
|
||||
dropdown: appType
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAppType(arr) {
|
||||
const searchAppType = []
|
||||
if (arr.length < 1) return searchAppType
|
||||
arr.forEach((i) => {
|
||||
const option = {
|
||||
value: i.name,
|
||||
label: i.title
|
||||
}
|
||||
searchAppType.push(option)
|
||||
})
|
||||
return searchAppType
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -15,12 +15,12 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/applications/?category=cloud',
|
||||
columns: [
|
||||
'name', 'type', 'attrs.cluster',
|
||||
'name', 'type_display', 'attrs.cluster',
|
||||
'created_by', 'date_created', 'date_updated', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: ['name', 'type', 'attrs.cluster', 'comment', 'actions']
|
||||
default: ['name', 'type_display', 'attrs.cluster', 'comment', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
'attrs.cluster': {
|
||||
@@ -29,8 +29,8 @@ export default {
|
||||
comment: {
|
||||
width: '340px'
|
||||
},
|
||||
type: {
|
||||
width: '140px'
|
||||
type_display: {
|
||||
label: this.$t('applications.type')
|
||||
},
|
||||
actions: {
|
||||
prop: 'actions',
|
||||
|
||||
@@ -17,17 +17,16 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/applications/?category=remote_app',
|
||||
columns: [
|
||||
'name', 'type', 'attrs.asset',
|
||||
'name', 'type_display', 'attrs.asset',
|
||||
'created_by', 'date_created', 'date_updated', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: ['name', 'type', 'attrs.asset', 'comment', 'actions']
|
||||
default: ['name', 'type_display', 'attrs.asset', 'comment', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
type: {
|
||||
displayKey: 'get_type_display',
|
||||
width: '140px'
|
||||
type_display: {
|
||||
label: this.$t('applications.type')
|
||||
},
|
||||
'attrs.asset': {
|
||||
label: this.$t('assets.Assets'),
|
||||
@@ -67,7 +66,14 @@ export default {
|
||||
hasImport: false,
|
||||
// createRoute: 'RemoteAppCreate',
|
||||
searchConfig: {
|
||||
exclude: ['category', 'type']
|
||||
exclude: ['category', 'type'],
|
||||
options: [
|
||||
{
|
||||
value: 'type',
|
||||
label: this.$t('applications.type'),
|
||||
children: this.getCreateAppType()
|
||||
}
|
||||
]
|
||||
},
|
||||
moreCreates: {
|
||||
dropdown: this.getCreateAppType(),
|
||||
@@ -85,6 +91,8 @@ export default {
|
||||
const item = { ...REMOTE_APP_TYPE_META_MAP[value] }
|
||||
item.can = true
|
||||
item.has = true
|
||||
item.value = item.name
|
||||
item.label = item.title
|
||||
extraMoreActions.push(item)
|
||||
}
|
||||
return extraMoreActions
|
||||
|
||||
@@ -88,7 +88,7 @@ export default {
|
||||
'protocols', 'platform', 'hardware_info', 'model',
|
||||
'cpu_model', 'cpu_cores', 'cpu_count', 'cpu_vcpus',
|
||||
'disk_info', 'disk_total', 'memory', 'os', 'os_arch',
|
||||
'os_version', 'number', 'vendor', 'sn',
|
||||
'os_version', 'number', 'vendor', 'sn', 'is_active',
|
||||
'connectivity', 'labels_display',
|
||||
'created_by', 'date_created', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
},
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'ip', 'port', 'protocol', 'domain']],
|
||||
[this.$t('assets.Auth'), ['username', 'password', 'private_key']],
|
||||
[this.$t('assets.Auth'), ['username', 'password', 'private_key', 'passphrase']],
|
||||
[this.$t('common.Other'), ['is_active', 'comment']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
|
||||
@@ -25,8 +25,8 @@ export default {
|
||||
auto_push: false
|
||||
},
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'login_mode', 'username', 'priority', 'protocol']],
|
||||
[this.$t('common.Auth'), ['password']],
|
||||
[this.$t('common.Basic'), ['name', 'username', 'priority', 'protocol']],
|
||||
[this.$t('common.Auth'), ['login_mode', 'password']],
|
||||
[this.$t('common.Command filter'), ['cmd_filters']],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
|
||||
@@ -47,6 +47,7 @@ export default {
|
||||
case 'postgresql':
|
||||
case 'mariadb':
|
||||
case 'sqlserver':
|
||||
case 'redis':
|
||||
return Database
|
||||
case 'k8s':
|
||||
return K8S
|
||||
|
||||
@@ -31,7 +31,7 @@ export default {
|
||||
},
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'protocol', 'username', 'username_same_with_user']],
|
||||
[this.$t('common.Auth'), ['login_mode', 'auto_generate_key', 'password', 'private_key']],
|
||||
[this.$t('common.Auth'), ['login_mode', 'auto_generate_key', 'password', 'private_key', 'passphrase']],
|
||||
[this.$t('assets.AutoPush'), ['auto_push', 'sudo', 'shell', 'home', 'system_groups']],
|
||||
[this.$t('common.Command filter'), ['cmd_filters']],
|
||||
[this.$t('assets.UserSwitch'), ['su_enabled', 'su_from']],
|
||||
@@ -41,6 +41,7 @@ export default {
|
||||
login_mode: fields.login_mode,
|
||||
username: fields.username,
|
||||
private_key: fields.private_key,
|
||||
passphrase: fields.passphrase,
|
||||
username_same_with_user: fields.username_same_with_user,
|
||||
auto_generate_key: fields.auto_generate_key,
|
||||
protocol: fields.protocol,
|
||||
|
||||
@@ -31,6 +31,8 @@ function getFields() {
|
||||
this.fieldsMeta.username.rules[0].required = false
|
||||
} else if (form.username_same_with_user) {
|
||||
this.fieldsMeta.username.rules[0].required = false
|
||||
} else if (form.protocol === 'redis') {
|
||||
this.fieldsMeta.username.rules[0].required = false
|
||||
} else {
|
||||
this.fieldsMeta.username.rules[0].required = true
|
||||
}
|
||||
@@ -152,7 +154,6 @@ function getFields() {
|
||||
}
|
||||
|
||||
const password = {
|
||||
helpText: this.$t('assets.PasswordHelpMessage'),
|
||||
component: UpdateToken,
|
||||
hidden: form => {
|
||||
if (form.login_mode !== 'auto' || form.auto_generate_key) {
|
||||
@@ -164,6 +165,16 @@ function getFields() {
|
||||
}
|
||||
}
|
||||
|
||||
const passphrase = {
|
||||
component: UpdateToken,
|
||||
hidden: (form) => {
|
||||
if (form.login_mode !== 'auto') {
|
||||
return true
|
||||
}
|
||||
return form.auto_generate_key === true
|
||||
}
|
||||
}
|
||||
|
||||
const system_groups = {
|
||||
label: this.$t('assets.LinuxUserAffiliateGroup'),
|
||||
hidden: (item) => !item.auto_push || item.username_same_with_user,
|
||||
@@ -184,6 +195,7 @@ function getFields() {
|
||||
auto_push: auto_push,
|
||||
update_password: update_password,
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
system_groups: system_groups,
|
||||
type: type
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export default {
|
||||
title: 'MySQL',
|
||||
type: 'primary',
|
||||
has: true,
|
||||
group: this.$t('assets.DatabaseProtocol')
|
||||
group: this.$t('assets.RDBProtocol')
|
||||
},
|
||||
{
|
||||
name: 'PostgreSQL',
|
||||
@@ -131,6 +131,13 @@ export default {
|
||||
type: 'primary',
|
||||
has: this.$store.getters.hasValidLicense
|
||||
},
|
||||
{
|
||||
name: 'Redis',
|
||||
title: 'Redis',
|
||||
type: 'primary',
|
||||
has: true,
|
||||
group: this.$t('assets.NoSQLProtocol')
|
||||
},
|
||||
{
|
||||
name: 'K8S',
|
||||
title: 'K8S',
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import { getDayFuture } from '@/utils/common'
|
||||
import PermissionFormActionField from '../components/PermissionFormActionField'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -29,9 +30,10 @@ export default {
|
||||
[this.$t('common.Basic'), ['name']],
|
||||
[this.$t('perms.User'), ['users', 'user_groups']],
|
||||
[this.$t('assets.Applications'), ['category', 'type', 'applications', 'system_users']],
|
||||
[this.$t('common.action'), ['actions']],
|
||||
[this.$t('common.Other'), ['is_active', 'date_start', 'date_expired', 'comment']]
|
||||
],
|
||||
url: '/api/v1/perms/application-permissions/',
|
||||
url: `/api/v1/perms/application-permissions/?category=${this.$route.query.category}&type=${this.$route.query.type}`,
|
||||
fieldsMeta: {
|
||||
users: {
|
||||
el: {
|
||||
@@ -101,7 +103,9 @@ export default {
|
||||
label: this.$t('common.dateExpired')
|
||||
},
|
||||
actions: {
|
||||
label: this.$t('perms.Actions')
|
||||
label: this.$t('perms.Actions'),
|
||||
component: PermissionFormActionField,
|
||||
helpText: this.$t('common.actionsTips')
|
||||
},
|
||||
is_active: {
|
||||
type: 'checkbox'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import AssetPermissionFormActionField from './components/AssetPermissionFormActionField'
|
||||
import PermissionFormActionField from '../components/PermissionFormActionField'
|
||||
import AssetSelect from '@/components/AssetSelect'
|
||||
import { getDayFuture } from '@/utils/common'
|
||||
|
||||
@@ -24,7 +24,6 @@ export default {
|
||||
return {
|
||||
initial: {
|
||||
is_active: true,
|
||||
actions: ['all', 'connect', 'updownload', 'upload_file', 'download_file'],
|
||||
date_start: new Date().toISOString(),
|
||||
date_expired: getDayFuture(36500, new Date()).toISOString(),
|
||||
nodes: nodesInitial,
|
||||
@@ -92,7 +91,7 @@ export default {
|
||||
},
|
||||
actions: {
|
||||
label: this.$t('perms.Actions'),
|
||||
component: AssetPermissionFormActionField,
|
||||
component: PermissionFormActionField,
|
||||
helpText: this.$t('common.actionsTips')
|
||||
},
|
||||
date_start: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-tree
|
||||
:data="data"
|
||||
:data="iData"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
:default-expand-all="false"
|
||||
@@ -13,11 +13,15 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AssetPermissionFormActionField',
|
||||
name: 'PermissionFormActionField',
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => ['all', 'connect', 'upload_file', 'download_file', 'updownload', 'clipboard_copy_paste', 'clipboard_copy', 'clipboard_paste']
|
||||
default: () => []
|
||||
},
|
||||
choices: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -26,7 +30,7 @@ export default {
|
||||
children: 'children',
|
||||
label: 'label'
|
||||
},
|
||||
data: [
|
||||
fullChoicesTreeNodes: [
|
||||
{
|
||||
id: 'all',
|
||||
label: this.$t('perms.all'),
|
||||
@@ -68,7 +72,34 @@ export default {
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
choicesIDs() {
|
||||
return this.choices.map((v) => v.value)
|
||||
},
|
||||
iData() {
|
||||
this.$log.debug('choices: ', this.choicesIDs)
|
||||
const fullTreeNodes = _.cloneDeep(this.fullChoicesTreeNodes)
|
||||
const treeNodes = this.trimChoicesTreeNodes(fullTreeNodes)
|
||||
this.$log.debug('choicesTreeNodes: ', treeNodes)
|
||||
return treeNodes
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
trimChoicesTreeNodes(treeNodes) {
|
||||
const newTreeNodes = []
|
||||
for (const treeNode of treeNodes) {
|
||||
if (!this.choicesIDs.includes(treeNode.id)) {
|
||||
continue
|
||||
}
|
||||
let children = treeNode.children || []
|
||||
if (children.length !== 0) {
|
||||
children = this.trimChoicesTreeNodes(children)
|
||||
treeNode.children = children
|
||||
}
|
||||
newTreeNodes.push(treeNode)
|
||||
}
|
||||
return newTreeNodes
|
||||
},
|
||||
handleCheckChange(data, obj) {
|
||||
const checkedKeys = obj.checkedKeys
|
||||
if (checkedKeys.length !== 0) {
|
||||
@@ -43,6 +43,7 @@ export const REMOTE_APP = [
|
||||
]
|
||||
|
||||
export const MYSQL = 'mysql'
|
||||
export const REDIS = 'redis'
|
||||
export const ORACLE = 'oracle'
|
||||
export const POSTGRESQL = 'postgresql'
|
||||
export const MARIADB = 'mariadb'
|
||||
@@ -56,7 +57,7 @@ export const DATABASE = [
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true,
|
||||
group: i18n.t('applications.Database')
|
||||
group: i18n.t('applications.RDBProtocol')
|
||||
},
|
||||
{
|
||||
name: ORACLE,
|
||||
@@ -85,6 +86,14 @@ export const DATABASE = [
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
},
|
||||
{
|
||||
name: REDIS,
|
||||
title: i18n.t(`applications.applicationsType.${REDIS}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true,
|
||||
group: i18n.t('applications.NoSQLProtocol')
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export default {
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
'expandCol', 'input', 'risk_level', 'user',
|
||||
'expandCol', 'input', 'risk_level', 'user', 'remote_addr',
|
||||
'asset', 'system_user', 'session', 'timestamp'
|
||||
],
|
||||
extraQuery: {
|
||||
|
||||
@@ -219,7 +219,7 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
let userAllOrgIds = this.$store.state.users.profile['user_all_orgs']
|
||||
const currentOrgId = this.$store.getters.currentOrg.id
|
||||
const currentOrgId = this.$store.getters.currentOrg ? this.$store.getters.currentOrg.id : null
|
||||
userAllOrgIds = userAllOrgIds ? userAllOrgIds.map(i => i.id) : []
|
||||
if (userAllOrgIds.length > 0) {
|
||||
if (userAllOrgIds.includes(currentOrgId)) {
|
||||
|
||||
@@ -40,66 +40,73 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
detailCardItems() {
|
||||
const obj = this.object || {}
|
||||
return [
|
||||
{
|
||||
key: this.$t('common.Number'),
|
||||
value: obj.serial_num
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.status'),
|
||||
value: this.object.status,
|
||||
value: obj.status,
|
||||
formatter: (item, val) => {
|
||||
return <el-tag type={this.statusMap.type} size='mini'> { this.statusMap.title }</el-tag>
|
||||
}
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.type'),
|
||||
value: this.object.type_display
|
||||
value: obj.type_display
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.user'),
|
||||
value: this.object['applicant_display']
|
||||
value: obj['applicant_display']
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.OrgName'),
|
||||
value: this.object['org_name']
|
||||
value: obj['org_name']
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateCreated'),
|
||||
value: toSafeLocalDateStr(this.object.date_created)
|
||||
value: toSafeLocalDateStr(obj.date_created)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Comment'),
|
||||
value: this.object.comment
|
||||
value: obj.comment
|
||||
}
|
||||
]
|
||||
},
|
||||
specialCardItems() {
|
||||
const meta = this.object.meta || {}
|
||||
return [
|
||||
{
|
||||
key: this.$t('applications.appType'),
|
||||
value: `${this.object.meta['apply_category_display']} / ${this.object.meta['apply_type_display']} `
|
||||
value: `${meta['apply_category_display']} / ${meta['apply_type_display']} `
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.appName'),
|
||||
value: this.object.meta.apply_applications_display.join(', ')
|
||||
value: meta?.apply_applications_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.SystemUser'),
|
||||
value: this.object.meta.apply_system_users_display.join(', ')
|
||||
value: meta?.apply_system_users_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateStart'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_start)
|
||||
value: toSafeLocalDateStr(meta.apply_date_start)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateExpired'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_expired)
|
||||
value: toSafeLocalDateStr(meta.apply_date_expired)
|
||||
}
|
||||
]
|
||||
},
|
||||
assignedCardItems() {
|
||||
const vm = this
|
||||
const meta = this.object.meta || {}
|
||||
return [
|
||||
{
|
||||
key: this.$t('tickets.PermissionName'),
|
||||
value: this.object.meta.apply_permission_name,
|
||||
value: meta.apply_permission_name,
|
||||
formatter: function(item, value) {
|
||||
const to = { name: 'ApplicationPermissionDetail', params: { id: vm.object.id }, query: { oid: vm.object.org_id }}
|
||||
if (vm.object.status === 'closed' && vm.object.state === 'approved') {
|
||||
@@ -111,19 +118,19 @@ export default {
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.appName'),
|
||||
value: this.object.meta.apply_applications_display.join(', ')
|
||||
value: meta?.apply_applications_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.SystemUser'),
|
||||
value: this.object.meta.apply_system_users_display.join(', ')
|
||||
value: meta?.apply_system_users_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateStart'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_start)
|
||||
value: toSafeLocalDateStr(meta.apply_date_start)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateExpired'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_expired)
|
||||
value: toSafeLocalDateStr(meta.apply_date_expired)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
import { getDaysFuture } from '@/utils/common'
|
||||
import AssetPermissionFormActionField from '@/views/perms/AssetPermission/components/AssetPermissionFormActionField'
|
||||
import PermissionFormActionField from '@/views/perms/components/PermissionFormActionField'
|
||||
export default {
|
||||
components: {
|
||||
GenericCreateUpdatePage
|
||||
@@ -50,7 +50,7 @@ export default {
|
||||
fieldsMeta: {
|
||||
apply_actions: {
|
||||
label: this.$t('perms.Actions'),
|
||||
component: AssetPermissionFormActionField,
|
||||
component: PermissionFormActionField,
|
||||
helpText: this.$t('common.actionsTips')
|
||||
},
|
||||
apply_nodes: {
|
||||
@@ -131,7 +131,7 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
let userAllOrgIds = this.$store.state.users.profile['user_all_orgs']
|
||||
const currentOrgId = this.$store.getters.currentOrg.id
|
||||
const currentOrgId = this.$store.getters.currentOrg ? this.$store.getters.currentOrg.id : null
|
||||
userAllOrgIds = userAllOrgIds ? userAllOrgIds.map(i => i.id) : []
|
||||
if (userAllOrgIds.length > 0) {
|
||||
if (userAllOrgIds.includes(currentOrgId)) {
|
||||
|
||||
@@ -38,66 +38,73 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
detailCardItems() {
|
||||
const obj = this.object || {}
|
||||
return [
|
||||
{
|
||||
key: this.$t('common.Number'),
|
||||
value: obj.serial_num
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.status'),
|
||||
value: this.object.state,
|
||||
value: obj.state,
|
||||
formatter: (item, val) => {
|
||||
return <el-tag type={this.statusMap.type} size='mini'> { this.statusMap.title }</el-tag>
|
||||
}
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.type'),
|
||||
value: this.object.type_display
|
||||
value: obj.type_display
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.user'),
|
||||
value: this.object['applicant_display']
|
||||
value: obj['applicant_display']
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.OrgName'),
|
||||
value: this.object.org_name
|
||||
value: obj.org_name
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateCreated'),
|
||||
value: toSafeLocalDateStr(this.object.date_created)
|
||||
value: toSafeLocalDateStr(obj.date_created)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Comment'),
|
||||
value: this.object.comment
|
||||
value: obj.comment
|
||||
}
|
||||
]
|
||||
},
|
||||
specialCardItems() {
|
||||
const meta = this.object.meta || {}
|
||||
return [
|
||||
{
|
||||
key: this.$t('perms.Node'),
|
||||
value: this.object.meta.apply_nodes_display.join(', ')
|
||||
value: meta?.apply_nodes_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.Asset'),
|
||||
value: this.object.meta.apply_assets_display.join(', ')
|
||||
value: meta?.apply_assets_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.SystemUser'),
|
||||
value: this.object.meta.apply_system_users_display.join(', ')
|
||||
value: meta?.apply_system_users_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Action'),
|
||||
value: forMatAction(this, this.object.meta['apply_actions_display'])
|
||||
value: forMatAction(this, meta['apply_actions_display'])
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateStart'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_start)
|
||||
value: toSafeLocalDateStr(meta.apply_date_start)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateExpired'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_expired)
|
||||
value: toSafeLocalDateStr(meta.apply_date_expired)
|
||||
}
|
||||
]
|
||||
},
|
||||
assignedCardItems() {
|
||||
const vm = this
|
||||
const meta = this.object.meta || {}
|
||||
return [
|
||||
{
|
||||
key: this.$t('tickets.PermissionName'),
|
||||
@@ -113,27 +120,27 @@ export default {
|
||||
},
|
||||
{
|
||||
key: this.$t('perms.Node'),
|
||||
value: this.object.meta.apply_nodes_display.join(', ')
|
||||
value: meta?.apply_nodes_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Asset'),
|
||||
value: this.object.meta.apply_assets_display.join(', ')
|
||||
value: meta?.apply_assets_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('tickets.SystemUser'),
|
||||
value: this.object.meta.apply_system_users_display.join(', ')
|
||||
value: meta?.apply_system_users_display?.join(', ') || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Action'),
|
||||
value: forMatAction(this, this.object.meta['apply_actions_display'])
|
||||
value: forMatAction(this, meta['apply_actions_display'])
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateStart'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_start)
|
||||
value: toSafeLocalDateStr(meta?.apply_date_start)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateExpired'),
|
||||
value: toSafeLocalDateStr(this.object.meta.apply_date_expired)
|
||||
value: toSafeLocalDateStr(meta?.apply_date_expired)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -26,6 +26,11 @@ export default {
|
||||
ticketTableConfig: {
|
||||
url: this.url,
|
||||
columns: [
|
||||
{
|
||||
prop: 'serial_num',
|
||||
label: this.$t('common.Number'),
|
||||
sortable: 'custom'
|
||||
},
|
||||
{
|
||||
prop: 'title',
|
||||
label: this.$t('tickets.title'),
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
</el-col>
|
||||
<el-col :span="6" :offset="1">
|
||||
<Steps :object="object" />
|
||||
<Session :object="object" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
@@ -17,9 +18,11 @@
|
||||
import Details from './Details'
|
||||
import Comments from './Comments'
|
||||
import Steps from './Steps'
|
||||
import Session from './Session'
|
||||
|
||||
export default {
|
||||
name: 'GenericTicketDetail',
|
||||
components: { Steps, Comments, Details },
|
||||
components: { Steps, Comments, Details, Session },
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
|
||||
140
src/views/tickets/components/Session.vue
Normal file
140
src/views/tickets/components/Session.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<IBox v-if="session.id" v-loading="loading" class="box">
|
||||
<div slot="header" class="clearfix ibox-title">
|
||||
<i class="fa fa-rocket" />
|
||||
{{ $t('sessions.session') }}
|
||||
</div>
|
||||
<div class="content">
|
||||
<el-row class="item">
|
||||
<el-col>
|
||||
<span class="item-label">{{ $t('tickets.status') }}:</span>
|
||||
<span class="item-value">
|
||||
{{ session.is_finished ? $t('sessions.noAlive') : $t('sessions.alive') }}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<span class="item-label">{{ $t('sessions.target') }}:</span>
|
||||
<span class="item-value">{{ session.asset }}</span>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<span class="item-label">{{ $t('sessions.remoteAddr') }}:</span>
|
||||
<span class="item-value">{{ session.remote_addr }}</span>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<span class="item-label">{{ $t('sessions.protocol') }}:</span>
|
||||
<span class="item-value">{{ session.protocol }}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-divider />
|
||||
<div class="bottom-btn">
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
:disabled="!session.can_terminate"
|
||||
@click="onConnect"
|
||||
>
|
||||
{{ $t('sessions.terminate') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!session.can_join"
|
||||
@click="onMonitor"
|
||||
>
|
||||
{{ $t('sessions.Monitor') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</IBox>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IBox from '@/components/IBox'
|
||||
|
||||
export default {
|
||||
components: { IBox },
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
session: {},
|
||||
curTimer: null,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.object.state !== 'open') {
|
||||
this.init()
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
clearTimeout(this.curTimer)
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.loading = true
|
||||
const url = `/api/v1/tickets/tickets/${this.object.id}/session/`
|
||||
this.$axios({
|
||||
url,
|
||||
method: 'get',
|
||||
disableFlashErrorMsg: true
|
||||
}).then(res => {
|
||||
this.session = res || {}
|
||||
}).catch(err => {
|
||||
this.$log.debug('error', err)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
onConnect() {
|
||||
const url = '/api/v1/terminal/tasks/kill-session-for-ticket/'
|
||||
const data = [this.session.id] || []
|
||||
this.$axios.post(url, data).then(res => {
|
||||
this.$message.success(this.$t('sessions.TerminateTaskSendSuccessMsg'))
|
||||
this.curTimer = setTimeout(() => {
|
||||
this.init()
|
||||
}, 50000)
|
||||
}).catch(err => {
|
||||
this.$message.error(err)
|
||||
})
|
||||
},
|
||||
onMonitor() {
|
||||
const joinUrl = `/luna/monitor/${this.session.id}`
|
||||
window.open(joinUrl, 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.box {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
&>>> .el-divider--horizontal {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
line-height: 2.5;
|
||||
font-size: 13px;
|
||||
color: #676A6C;
|
||||
.item-label {
|
||||
font-weight: 700;
|
||||
}
|
||||
.item-value {
|
||||
color: #676A6C;
|
||||
}
|
||||
&>>> .el-col {
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
.bottom-btn {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
12
yarn.lock
12
yarn.lock
@@ -10793,6 +10793,13 @@ vue-jest@^3.0.4:
|
||||
tsconfig "^7.0.0"
|
||||
vue-template-es2015-compiler "^1.6.0"
|
||||
|
||||
vue-json-editor@^1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-json-editor/-/vue-json-editor-1.4.3.tgz#004c9037ac91f16dd8fc558c9914e5f33a41d71c"
|
||||
integrity sha512-st9HdXBgCnyEmmfWrZQiKzp4KuYXzmYVUNDn5h6Fa18MrrGS1amnyUFyv7hQFsNBDW27B7BKkdGOqszYT1srAg==
|
||||
dependencies:
|
||||
vue "^2.2.6"
|
||||
|
||||
vue-loader@^15.7.0:
|
||||
version "15.9.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.1.tgz#bd2ab8f3d281e51d7b81d15390a58424d142243e"
|
||||
@@ -10850,6 +10857,11 @@ vue@2.6.11:
|
||||
resolved "https://registry.npm.taobao.org/vue/download/vue-2.6.11.tgz?cache=0&sync_timestamp=1587135947786&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue%2Fdownload%2Fvue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
|
||||
integrity sha1-dllNh31LEiNEBuhONSdcbVFBJcU=
|
||||
|
||||
vue@^2.2.6:
|
||||
version "2.6.14"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||
|
||||
vuejs-logger@^1.5.4:
|
||||
version "1.5.4"
|
||||
resolved "https://registry.npm.taobao.org/vuejs-logger/download/vuejs-logger-1.5.4.tgz#c8bb12ed29ca90b8087144a44ad852d9bd170c6e"
|
||||
|
||||
Reference in New Issue
Block a user