mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-14 11:55:34 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48beb502bd | ||
|
|
383a799c6a | ||
|
|
c378b2bf0d |
@@ -1,6 +1,8 @@
|
||||
# 全局环境变量 请勿随意改动
|
||||
ENV = 'development'
|
||||
|
||||
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = ''
|
||||
VUE_APP_PUBLIC_PATH = '/ui/'
|
||||
@@ -21,5 +23,4 @@ VUE_APP_LOGOUT_PATH = '/core/auth/logout/'
|
||||
|
||||
# Dev server for core proxy
|
||||
VUE_APP_CORE_HOST = 'http://localhost:8080'
|
||||
VUE_APP_CORE_WS = 'ws://localhost:8080'
|
||||
VUE_APP_ENV = 'development'
|
||||
|
||||
@@ -12,8 +12,8 @@ RUN npm config set sass_binary_site=${SASS_BINARY_SITE}
|
||||
RUN npm config set registry ${NPM_REGISTRY}
|
||||
RUN yarn config set registry ${NPM_REGISTRY}
|
||||
COPY package.json yarn.lock /data/
|
||||
RUN yarn install
|
||||
RUN npm rebuild node-sass
|
||||
COPY utils /data/utils/
|
||||
RUN ls && cd utils && bash -xieu build.sh dep
|
||||
|
||||
ADD . /data
|
||||
RUN cd utils && bash -xieu build.sh build
|
||||
|
||||
@@ -57,26 +57,6 @@ export function TestReplayStorage(id) {
|
||||
})
|
||||
}
|
||||
|
||||
function SetToDefaultStorage(url) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'patch',
|
||||
data: { 'is_default': true }
|
||||
})
|
||||
}
|
||||
|
||||
export function SetToDefaultCommandStorage(id) {
|
||||
return SetToDefaultStorage(
|
||||
`/api/v1/terminal/command-storages/${id}/`,
|
||||
)
|
||||
}
|
||||
|
||||
export function SetToDefaultReplayStorage(id) {
|
||||
return SetToDefaultStorage(
|
||||
`/api/v1/terminal/replay-storages/${id}/`,
|
||||
)
|
||||
}
|
||||
|
||||
export function getReplayStorage(id) {
|
||||
return request({
|
||||
url: `/api/v1/terminal/replay-storages/${id}/`,
|
||||
|
||||
@@ -51,7 +51,7 @@ export function refreshLdapUserCache() {
|
||||
})
|
||||
}
|
||||
|
||||
export function startLdapUserCache() {
|
||||
export function StartLdapUserCache() {
|
||||
return request({
|
||||
disableFlashErrorMsg: true,
|
||||
url: '/api/v1/settings/ldap/users/?cache_police=1',
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<MFAVerifyDialog
|
||||
@MFAVerifyDone="getAuthInfo"
|
||||
@MFAVerifyCancel="exit"
|
||||
/>
|
||||
<Dialog
|
||||
:title="dialogTitle"
|
||||
:show-confirm="false"
|
||||
:show-cancel="false"
|
||||
:destroy-on-close="true"
|
||||
:width="'50'"
|
||||
:visible.sync="showAuthInfo"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<div>
|
||||
<el-form label-position="right" label-width="80px" :model="authInfo">
|
||||
<el-form-item :label="this.$t('assets.Hostname')">
|
||||
<el-input v-model="account.hostname" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Username')">
|
||||
<el-input v-model="account['username']" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Password')">
|
||||
<el-input v-model="authInfo.password" type="password" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.SSHKey')">
|
||||
<el-input v-model="authInfo['private_key']" type="password" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
|
||||
export default {
|
||||
name: 'ShowSecretInfo',
|
||||
components: {
|
||||
Dialog,
|
||||
MFAVerifyDialog
|
||||
},
|
||||
props: {
|
||||
account: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogTitle: this.$t('common.ViewSecret'),
|
||||
authInfo: {},
|
||||
showAuthInfo: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAuthInfo()
|
||||
},
|
||||
methods: {
|
||||
getAuthInfo() {
|
||||
const url = `/api/v1/assets/account-secrets/${this.account.id}/`
|
||||
this.$axios.get(url, { disableFlashErrorMsg: true }).then(resp => {
|
||||
this.authInfo = resp
|
||||
this.showAuthInfo = true
|
||||
})
|
||||
},
|
||||
exit() {
|
||||
this.$emit('update:visible', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,92 +0,0 @@
|
||||
<template>
|
||||
<Dialog
|
||||
width="50"
|
||||
:title="this.$t('assets.UpdateAssetUserToken')"
|
||||
:destroy-on-close="true"
|
||||
v-bind="$attrs"
|
||||
@confirm="handleConfirm()"
|
||||
@cancel="handleCancel()"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<el-form label-position="right" label-width="80px">
|
||||
<el-form-item :label="this.$t('assets.Hostname')">
|
||||
<el-input v-model="account.hostname" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Username')">
|
||||
<el-input v-model="account['username']" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Password')">
|
||||
<el-input v-model="authInfo.password" type="password" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.SSHKey')">
|
||||
<input type="file" @change="onPrivateKeyLoaded">
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
export default {
|
||||
name: 'UpdateSecretInfo',
|
||||
components: {
|
||||
Dialog
|
||||
},
|
||||
props: {
|
||||
account: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
authInfo: {
|
||||
password: '',
|
||||
private_key: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleConfirm() {
|
||||
const data = {}
|
||||
if (this.authInfo.password !== '') {
|
||||
data.password = this.authInfo.password
|
||||
}
|
||||
if (this.authInfo.private_key !== '') {
|
||||
data.private_key = this.authInfo.private_key
|
||||
}
|
||||
this.$axios.patch(
|
||||
`/api/v1/assets/accounts/${this.account.id}/`,
|
||||
data
|
||||
).then(res => {
|
||||
this.authInfo = { password: '', private_key: '' }
|
||||
this.$message.success(this.$tc('common.updateSuccessMsg'))
|
||||
this.$emit('updateAuthDone', res)
|
||||
this.$emit('update:visible', false)
|
||||
}).catch(err => {
|
||||
const errMsg = Object.values(err.response.data).join(', ')
|
||||
this.$message.error(this.$tc('common.updateErrorMsg') + ' ' + errMsg)
|
||||
this.$emit('update:visible', true)
|
||||
})
|
||||
},
|
||||
handleCancel() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
onPrivateKeyLoaded(e) {
|
||||
const vm = this
|
||||
// TODO 校验文件类型
|
||||
const reader = new FileReader()
|
||||
reader.onload = function() {
|
||||
vm.authInfo.private_key = this.result
|
||||
}
|
||||
reader.readAsText(
|
||||
e.target.files[0]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,31 +0,0 @@
|
||||
import { ChoicesFormatter } from '@/components/TableFormatters'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import i18n from '@/i18n/i18n'
|
||||
|
||||
export const connectivityMeta = {
|
||||
label: i18n.t('assets.Reachable'),
|
||||
formatter: ChoicesFormatter,
|
||||
formatterArgs: {
|
||||
iconChoices: {
|
||||
ok: 'fa-check text-primary',
|
||||
failed: 'fa-times text-danger',
|
||||
unknown: 'fa-circle text-warning'
|
||||
},
|
||||
hasTips: true,
|
||||
getTips: ({ row, cellValue }) => {
|
||||
const mapper = {
|
||||
'ok': i18n.t('assets.Reachable'),
|
||||
'failed': i18n.t('assets.Unreachable'),
|
||||
'unknown': i18n.t('assets.Unknown')
|
||||
}
|
||||
let tips = mapper[cellValue]
|
||||
if (row['date_verified']) {
|
||||
const datetime = toSafeLocalDateStr(row['date_verified'])
|
||||
tips += '<br> ' + datetime
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
width: '90px',
|
||||
align: 'center'
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
<ShowSecretInfo v-if="showViewSecretDialog" :visible.sync="showViewSecretDialog" :account="account" />
|
||||
<UpdateSecretInfo :visible.sync="showUpdateSecretDialog" :account="account" @updateAuthDone="onUpdateAuthDone" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListTable from '@/components/ListTable/index'
|
||||
import { ActionsFormatter, DetailFormatter, DisplayFormatter } from '@/components/TableFormatters'
|
||||
import ShowSecretInfo from './ShowSecretInfo'
|
||||
import UpdateSecretInfo from './UpdateSecretInfo'
|
||||
import { connectivityMeta } from './const'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
|
||||
export default {
|
||||
name: 'AccountListTable',
|
||||
components: {
|
||||
ListTable,
|
||||
UpdateSecretInfo,
|
||||
ShowSecretInfo
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
exportUrl: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.url.replace('/assets/accounts/', '/assets/account-secrets/')
|
||||
}
|
||||
},
|
||||
hasLeftActions: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
otherActions: {
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
hasClone: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showViewSecretDialog: false,
|
||||
showUpdateSecretDialog: false,
|
||||
account: {},
|
||||
tableConfig: {
|
||||
url: this.url,
|
||||
columns: [
|
||||
'hostname', 'ip', 'username', 'version', 'connectivity',
|
||||
'systemuser', 'date_created', 'date_updated', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['username', 'actions'],
|
||||
default: ['hostname', 'ip', 'username', 'version', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
prop: 'hostname',
|
||||
label: this.$t('assets.Hostname'),
|
||||
showOverflowTooltip: true,
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
getRoute({ row }) {
|
||||
return {
|
||||
name: 'AssetDetail',
|
||||
params: { id: row.asset }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ip: {
|
||||
width: '120px'
|
||||
},
|
||||
username: {
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
systemuser: {
|
||||
formatter: DisplayFormatter
|
||||
},
|
||||
version: {
|
||||
width: '70px'
|
||||
},
|
||||
connectivity: connectivityMeta,
|
||||
actions: {
|
||||
formatter: ActionsFormatter,
|
||||
formatterArgs: {
|
||||
hasUpdate: false, // can set function(row, value)
|
||||
hasDelete: false, // can set function(row, value)
|
||||
hasClone: this.hasClone,
|
||||
moreActionsTitle: this.$t('common.More'),
|
||||
extraActions: [
|
||||
{
|
||||
name: 'View',
|
||||
title: this.$t('common.View'),
|
||||
type: 'primary',
|
||||
callback: function({ row }) {
|
||||
this.account = row
|
||||
this.showViewSecretDialog = true
|
||||
}.bind(this)
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
title: this.$t('common.Delete'),
|
||||
type: 'primary',
|
||||
callback: ({ row }) => {
|
||||
this.$axios.delete(`/api/v1/assets/accounts/${row.id}/`).then(() => {
|
||||
this.$message.success(this.$tc('common.deleteSuccessMsg'))
|
||||
this.$refs.ListTable.reloadTable()
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test',
|
||||
title: this.$t('common.Test'),
|
||||
callback: ({ row }) => {
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/accounts/${row.id}/verify/`,
|
||||
{ action: 'test' }
|
||||
).then(res => {
|
||||
openTaskPage(res['task'])
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
title: this.$t('common.Update'),
|
||||
can: !this.$store.getters.currentOrgIsRoot,
|
||||
callback: function({ row }) {
|
||||
this.account = row
|
||||
this.showUpdateSecretDialog = true
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: this.hasLeftActions,
|
||||
hasMoreActions: false,
|
||||
hasImport: false,
|
||||
hasExport: true,
|
||||
exportOptions: {
|
||||
url: this.exportUrl,
|
||||
mfaVerifyRequired: true
|
||||
},
|
||||
searchConfig: {
|
||||
exclude: ['systemuser', 'asset']
|
||||
},
|
||||
hasSearch: true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
url(iNew) {
|
||||
this.$set(this.tableConfig, 'url', iNew)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.otherActions) {
|
||||
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
|
||||
for (const item of this.otherActions) {
|
||||
actionColumn.formatterArgs.extraActions.push(item)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onUpdateAuthDone(account) {
|
||||
Object.assign(this.account, account)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,80 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<MFAVerifyDialog
|
||||
@MFAVerifyDone="getAuthInfo"
|
||||
@MFAVerifyCancel="exit"
|
||||
/>
|
||||
<Dialog
|
||||
:title="dialogTitle"
|
||||
:show-confirm="false"
|
||||
:show-cancel="false"
|
||||
:destroy-on-close="true"
|
||||
:width="'50'"
|
||||
:visible.sync="showAuthInfo"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<div>
|
||||
<el-form label-position="right" label-width="80px" :model="authInfo">
|
||||
<el-form-item :label="this.$t('applications.appName')">
|
||||
<el-input v-model="account['app_display']" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Username')">
|
||||
<el-input v-model="account['username']" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Password')">
|
||||
<el-input v-model="authInfo.password" type="password" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
|
||||
export default {
|
||||
name: 'ShowSecretInfo',
|
||||
components: {
|
||||
Dialog,
|
||||
MFAVerifyDialog
|
||||
},
|
||||
props: {
|
||||
account: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogTitle: this.$t('common.ViewSecret'),
|
||||
authInfo: {},
|
||||
showAuthInfo: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAuthInfo()
|
||||
},
|
||||
methods: {
|
||||
getAuthInfo() {
|
||||
const url = `/api/v1/applications/account-secrets/${this.account.id}/`
|
||||
this.$axios.get(url, { disableFlashErrorMsg: true }).then(resp => {
|
||||
this.authInfo = resp
|
||||
this.showAuthInfo = true
|
||||
})
|
||||
},
|
||||
exit() {
|
||||
this.$emit('update:visible', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,31 +0,0 @@
|
||||
import { ChoicesFormatter } from '@/components/TableFormatters'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import i18n from '@/i18n/i18n'
|
||||
|
||||
export const connectivityMeta = {
|
||||
label: i18n.t('assets.Reachable'),
|
||||
formatter: ChoicesFormatter,
|
||||
formatterArgs: {
|
||||
iconChoices: {
|
||||
ok: 'fa-check text-primary',
|
||||
failed: 'fa-times text-danger',
|
||||
unknown: 'fa-circle text-warning'
|
||||
},
|
||||
hasTips: true,
|
||||
getTips: ({ row, cellValue }) => {
|
||||
const mapper = {
|
||||
'ok': i18n.t('assets.Reachable'),
|
||||
'failed': i18n.t('assets.Unreachable'),
|
||||
'unknown': i18n.t('assets.Unknown')
|
||||
}
|
||||
let tips = mapper[cellValue]
|
||||
if (row['date_verified']) {
|
||||
const datetime = toSafeLocalDateStr(row['date_verified'])
|
||||
tips += '<br> ' + datetime
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
width: '90px',
|
||||
align: 'center'
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
<ShowSecretInfo v-if="showViewSecretDialog" :visible.sync="showViewSecretDialog" :account="account" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListTable from '@/components/ListTable/index'
|
||||
import { ActionsFormatter, DetailFormatter } from '@/components/TableFormatters'
|
||||
import ShowSecretInfo from './ShowSecretInfo'
|
||||
|
||||
export default {
|
||||
name: 'Detail',
|
||||
components: {
|
||||
ListTable,
|
||||
ShowSecretInfo
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
exportUrl: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.url.replace('/applications/accounts/', '/applications/account-secrets/')
|
||||
}
|
||||
},
|
||||
hasLeftActions: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
otherActions: {
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
hasClone: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showViewSecretDialog: false,
|
||||
showUpdateSecretDialog: false,
|
||||
account: {},
|
||||
tableConfig: {
|
||||
url: this.url,
|
||||
columns: [
|
||||
'app_display', 'username', 'category_display',
|
||||
'type_display', 'systemuser', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
app_display: {
|
||||
showOverflowTooltip: true,
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
getRoute({ row }) {
|
||||
switch (row['category']) {
|
||||
case 'remote_app':
|
||||
return {
|
||||
name: 'RemoteAppDetail',
|
||||
params: { id: row.app }
|
||||
}
|
||||
case 'db':
|
||||
return {
|
||||
name: 'DatabaseAppDetail',
|
||||
params: { id: row.app }
|
||||
}
|
||||
default:
|
||||
return {
|
||||
name: 'KubernetesAppDetail',
|
||||
params: { id: row.app }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
username: {
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
systemuser: {
|
||||
showOverflowTooltip: true,
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
getTitle({ row }) {
|
||||
return row.systemuser_display
|
||||
},
|
||||
getRoute({ row }) {
|
||||
return {
|
||||
name: 'SystemUserDetail',
|
||||
params: { id: row.systemuser }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
formatter: ActionsFormatter,
|
||||
formatterArgs: {
|
||||
hasUpdate: false, // can set function(row, value)
|
||||
hasDelete: false, // can set function(row, value)
|
||||
hasClone: this.hasClone,
|
||||
moreActionsTitle: this.$t('common.More'),
|
||||
extraActions: [
|
||||
{
|
||||
name: 'View',
|
||||
title: this.$t('common.View'),
|
||||
type: 'primary',
|
||||
callback: function({ row }) {
|
||||
this.account = row
|
||||
this.showViewSecretDialog = true
|
||||
}.bind(this)
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
title: this.$t('common.Update'),
|
||||
can: !this.$store.getters.currentOrgIsRoot,
|
||||
callback: function({ row }) {
|
||||
this.$message.success(this.$tc('applications.updateAccountMsg'))
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: this.hasLeftActions,
|
||||
hasMoreActions: false,
|
||||
hasImport: false,
|
||||
hasExport: true,
|
||||
exportOptions: {
|
||||
url: this.exportUrl,
|
||||
mfaVerifyRequired: true
|
||||
},
|
||||
searchConfig: {
|
||||
exclude: ['systemuser', 'asset']
|
||||
},
|
||||
hasSearch: true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
url(iNew) {
|
||||
this.$set(this.tableConfig, 'url', iNew)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.otherActions) {
|
||||
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
|
||||
for (const item of this.otherActions) {
|
||||
actionColumn.formatterArgs.extraActions.push(item)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onUpdateAuthDone(account) {
|
||||
Object.assign(this.account, account)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,13 +1,6 @@
|
||||
<template>
|
||||
<div class="asset-select-dialog">
|
||||
<Select2
|
||||
ref="select2"
|
||||
v-model="select2Config.value"
|
||||
v-bind="select2Config"
|
||||
@input="onInputChange"
|
||||
@focus.stop="handleFocus"
|
||||
v-on="$listeners"
|
||||
/>
|
||||
<Select2 ref="select2" v-bind="select2Config" @input="onInputChange" @focus.stop="handleFocus" v-on="$listeners" />
|
||||
<Dialog
|
||||
v-if="dialogVisible"
|
||||
:title="this.$t('assets.Assets')"
|
||||
@@ -83,7 +76,7 @@ export default {
|
||||
select2Config: select2Config,
|
||||
dialogSelect2Config: select2Config,
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/assets/?fields_size=mini',
|
||||
url: '/api/v1/assets/assets/',
|
||||
hasTree: true,
|
||||
canSelect: this.canSelect,
|
||||
columns: [
|
||||
@@ -101,18 +94,6 @@ export default {
|
||||
prop: 'ip',
|
||||
label: this.$t('assets.ipDomain'),
|
||||
sortable: 'custom'
|
||||
},
|
||||
{
|
||||
prop: 'platform',
|
||||
label: this.$t('assets.Platform'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
prop: 'protocols',
|
||||
formatter: function(row) {
|
||||
return <span> {row.protocols.toString()} </span>
|
||||
},
|
||||
label: this.$t('assets.Protocols')
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
|
||||
529
src/components/AssetUserTable/index.vue
Normal file
529
src/components/AssetUserTable/index.vue
Normal file
@@ -0,0 +1,529 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<ListTable ref="ListTable" :table-config="iTableConfig" :header-actions="headerActions" />
|
||||
<Dialog v-if="showMFADialog" width="50" :title="this.$t('common.MFAConfirm')" :visible.sync="showMFADialog" :show-confirm="false" :show-cancel="false" :destroy-on-close="true">
|
||||
<div v-if="MFAConfirmed">
|
||||
<el-form label-position="right" label-width="80px" :model="MFAInfo">
|
||||
<el-form-item :label="this.$t('assets.Hostname')">
|
||||
<el-input v-model="MFAInfo.hostname" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Username')">
|
||||
<el-input v-model="MFAInfo.username" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Password')">
|
||||
<el-input v-model="MFAInfo.password" type="password" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-row v-else :gutter="20">
|
||||
<el-col :span="4">
|
||||
<div style="line-height: 34px;text-align: center">MFA</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-input v-model="MFAInput" />
|
||||
<span class="help-tips help-block">{{ $t('common.MFARequireForSecurity') }}</span>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="MFAConfirm">{{ this.$t('common.Confirm') }}</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
<Dialog width="50" :title="this.$t('assets.UpdateAssetUserToken')" :visible.sync="showDialog" @confirm="handleConfirm()" @cancel="handleCancel()">
|
||||
<el-form label-position="right" label-width="80px" :model="dialogInfo">
|
||||
<el-form-item :label="this.$t('assets.Hostname')">
|
||||
<el-input v-model="dialogInfo.hostname" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Username')">
|
||||
<el-input v-model="dialogInfo.username" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Password')">
|
||||
<el-input v-model="dialogInfo.password" type="password" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.sshkey')">
|
||||
<input type="file" @change="Onchange">
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
<Dialog :title="$t('common.Export')" :visible.sync="showExportDialog" :destroy-on-close="true" @confirm="handleExportConfirm()" @cancel="handleExportCancel()">
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportTypeOption">
|
||||
<el-radio v-for="option of exportTypeOptions" :key="option.value" style="padding: 10px 20px;" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('common.imExport.ExportRange')" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportOption">
|
||||
<el-radio v-for="option of exportOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import ListTable from '@/components/ListTable/index'
|
||||
import Dialog from '@/components/Dialog'
|
||||
import { createSourceIdCache } from '@/api/common'
|
||||
import * as queryUtil from '@/components/DataTable/compenents/el-data-table/utils/query'
|
||||
import { ActionsFormatter, DateFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
name: 'Detail',
|
||||
components: {
|
||||
ListTable,
|
||||
Dialog
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
searchExclude: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
extraQuery: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
canExportAll: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
canExportSelected: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
canExportFiltered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasLeftActions: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
otherActions: {
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
handleExport: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
handleImport: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
hasImport: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasExport: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasClone: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
tableConfig: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
MFAConfirmed: false,
|
||||
MFAInput: '',
|
||||
MFAInfo: {
|
||||
asset: '',
|
||||
username: '',
|
||||
hostname: '',
|
||||
password: ''
|
||||
},
|
||||
showDialog: false,
|
||||
showMFADialog: false,
|
||||
dialogInfo: {
|
||||
asset: '',
|
||||
username: '',
|
||||
hostname: '',
|
||||
password: '',
|
||||
private_key: ''
|
||||
},
|
||||
selectedRows: '',
|
||||
dialogStatus: '',
|
||||
showExportDialog: false,
|
||||
exportOption: 'all',
|
||||
exportTypeOption: 'csv',
|
||||
defaultTableConfig: {
|
||||
url: this.url,
|
||||
columns: ['hostname', 'ip', 'username', 'version', 'date_created', 'actions'],
|
||||
columnsMeta: {
|
||||
'hostname': {
|
||||
label: this.$t('assets.Hostname'),
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
'ip': {
|
||||
label: this.$t('assets.ip'),
|
||||
width: '120px'
|
||||
},
|
||||
'username': {
|
||||
label: this.$t('assets.Username'),
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
'version': {
|
||||
label: this.$t('assets.Version'),
|
||||
width: '70px'
|
||||
},
|
||||
'date_created': {
|
||||
label: this.$t('assets.date_joined'),
|
||||
formatter: DateFormatter
|
||||
},
|
||||
'actions': {
|
||||
label: this.$t('common.Action'),
|
||||
align: 'center',
|
||||
width: 150,
|
||||
formatter: ActionsFormatter,
|
||||
formatterArgs: {
|
||||
hasUpdate: false, // can set function(row, value)
|
||||
hasDelete: false, // can set function(row, value)
|
||||
hasClone: this.hasClone,
|
||||
moreActionsTitle: this.$t('common.More'),
|
||||
extraActions: [
|
||||
{
|
||||
name: 'View',
|
||||
title: this.$t('common.View'),
|
||||
type: 'primary',
|
||||
callback: function(val) {
|
||||
this.dialogStatus = 'viewAutoInfo'
|
||||
this.MFAInfo.asset = val.row.id
|
||||
if (!this.needMFAVerify) {
|
||||
this.showMFADialog = true
|
||||
this.MFAConfirmed = true
|
||||
this.$axios.get(`/api/v1/assets/asset-user-auth-infos/${this.MFAInfo.asset}/`).then(res => {
|
||||
this.MFAConfirmed = true
|
||||
this.MFAInfo.hostname = res.hostname
|
||||
this.MFAInfo.password = res.password
|
||||
this.MFAInfo.username = res.username
|
||||
})
|
||||
} else {
|
||||
this.showMFADialog = true
|
||||
}
|
||||
}.bind(this)
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
title: this.$t('common.Delete'),
|
||||
type: 'primary',
|
||||
callback: (val) => {
|
||||
this.$axios.delete(`/api/v1/assets/asset-users/${val.row.id}/`).then(() => {
|
||||
this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
this.$refs.ListTable.reloadTable()
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test',
|
||||
title: this.$t('common.Test'),
|
||||
callback: (val) => {
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/asset-users/tasks/?id=${val.row.id}`,
|
||||
{ action: 'test' }
|
||||
).then(res => {
|
||||
window.open(`/#/ops/celery/task/${res.task}/log/`, '', 'width=900,height=600')
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
title: this.$t('common.Update'),
|
||||
can: !this.$store.getters.currentOrgIsRoot,
|
||||
callback: function(val) {
|
||||
this.showDialog = true
|
||||
this.dialogInfo.asset = val.row.asset
|
||||
this.dialogInfo.hostname = val.row.hostname
|
||||
this.dialogInfo.username = val.row.username
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
extraQuery: this.extraQuery || { latest: 1 }
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: this.hasLeftActions,
|
||||
hasMoreActions: false,
|
||||
hasImport: this.hasImport,
|
||||
hasExport: this.hasExport,
|
||||
hasSearch: true,
|
||||
searchConfig: {
|
||||
exclude: this.searchExclude,
|
||||
options: [
|
||||
{
|
||||
label: this.$t('assets.OnlyLatestVersion'),
|
||||
value: 'latest',
|
||||
children: [
|
||||
{
|
||||
label: this.$t('common.Yes'),
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: this.$t('common.No'),
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'MFA_TTl',
|
||||
'MFAVerifyAt',
|
||||
'publicSettings'
|
||||
]),
|
||||
needMFAVerify() {
|
||||
if (!this.publicSettings.SECURITY_VIEW_AUTH_NEED_MFA) {
|
||||
return false
|
||||
}
|
||||
const ttl = this.publicSettings.SECURITY_MFA_VERIFY_TTL
|
||||
const now = new Date()
|
||||
return !(this.MFAVerifyAt && (now - this.MFAVerifyAt) < ttl * 1000)
|
||||
},
|
||||
iTableConfig() {
|
||||
const columnsMeta = Object.assign({}, this.defaultTableConfig.columnsMeta, this.tableConfig.columnsMeta || {})
|
||||
const config = Object.assign(this.defaultTableConfig, this.tableConfig)
|
||||
config.columnsMeta = columnsMeta
|
||||
return config
|
||||
},
|
||||
exportOptions() {
|
||||
return [
|
||||
{
|
||||
label: this.$t('common.imExport.ExportAll'),
|
||||
value: 'all',
|
||||
can: this.canExportAll
|
||||
},
|
||||
{
|
||||
label: this.$t('common.imExport.ExportOnlySelectedItems'),
|
||||
value: 'selected',
|
||||
can: this.selectedRows.length > 0 && this.canExportSelected
|
||||
},
|
||||
{
|
||||
label: this.$t('common.imExport.ExportOnlyFiltered'),
|
||||
value: 'filtered',
|
||||
can: this.tableHasQuery() && this.canExportFiltered
|
||||
}
|
||||
]
|
||||
},
|
||||
exportTypeOptions() {
|
||||
return [
|
||||
{
|
||||
label: 'CSV',
|
||||
value: 'csv',
|
||||
can: true
|
||||
},
|
||||
{
|
||||
label: 'Excel',
|
||||
value: 'xlsx',
|
||||
can: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
url(iNew) {
|
||||
this.$set(this.iTableConfig, 'url', iNew)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.otherActions) {
|
||||
const actionColumn = this.iTableConfig.columns[this.iTableConfig.columns.length - 1]
|
||||
for (const item of this.otherActions) {
|
||||
actionColumn.formatterArgs.extraActions.push(item)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.headerActions.handleExport = this.handleExport || this.defaultHandleExport
|
||||
if (this.handleImport) {
|
||||
this.headerActions.handleImport = this.handleImport
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
MFAConfirm() {
|
||||
if (this.MFAInput.length !== 6) {
|
||||
return this.$message.error(this.$t('common.MFAErrorMsg'))
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/otp/verify/`, {
|
||||
code: this.MFAInput
|
||||
}
|
||||
).then(
|
||||
res => {
|
||||
this.$store.dispatch('users/setMFAVerify')
|
||||
if (this.dialogStatus === 'export') {
|
||||
this.showMFADialog = false
|
||||
this.showExportDialog = true
|
||||
} else {
|
||||
this.$axios.get(`/api/v1/assets/asset-user-auth-infos/${this.MFAInfo.asset}/`).then(res => {
|
||||
this.MFAConfirmed = true
|
||||
this.MFAInfo.hostname = res.hostname
|
||||
this.MFAInfo.password = res.password
|
||||
this.MFAInfo.username = res.username
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
handleMFAConfirm() {
|
||||
this.MFAInfo = {
|
||||
asset: '',
|
||||
username: '',
|
||||
hostname: '',
|
||||
password: ''
|
||||
}
|
||||
this.MFAInput = ''
|
||||
this.showMFADialog = false
|
||||
this.MFAConfirmed = false
|
||||
},
|
||||
handleCancel() {
|
||||
this.dialogInfo = {
|
||||
asset: '',
|
||||
username: '',
|
||||
hostname: '',
|
||||
password: '',
|
||||
private_key: ''
|
||||
}
|
||||
this.showDialog = false
|
||||
this.$refs.ListTable.reloadTable()
|
||||
},
|
||||
Onchange(e) {
|
||||
const vm = this
|
||||
// TODO 校验文件类型
|
||||
const reader = new FileReader()
|
||||
reader.onload = function() {
|
||||
vm.dialogInfo.private_key = this.result
|
||||
}
|
||||
reader.readAsText(
|
||||
e.target.files[0]
|
||||
)
|
||||
},
|
||||
handleConfirm() {
|
||||
const data = {
|
||||
asset: this.dialogInfo.asset,
|
||||
username: this.dialogInfo.username
|
||||
}
|
||||
if (this.dialogInfo.password !== '') {
|
||||
data.password = this.dialogInfo.password
|
||||
}
|
||||
if (this.dialogInfo.private_key !== '') {
|
||||
data.private_key = this.dialogInfo.private_key
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/asset-users/`,
|
||||
data
|
||||
).then(res => {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
}).catch(err => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + err))
|
||||
})
|
||||
this.dialogInfo = {
|
||||
asset: '',
|
||||
username: '',
|
||||
hostname: '',
|
||||
password: '',
|
||||
private_key: ''
|
||||
}
|
||||
this.showDialog = false
|
||||
this.$refs.ListTable.reloadTable()
|
||||
},
|
||||
tableQuery() {
|
||||
const listTableRef = this.$refs.ListTable
|
||||
if (!listTableRef) {
|
||||
return {}
|
||||
}
|
||||
const query = listTableRef.dataTable.getQuery()
|
||||
delete query['limit']
|
||||
delete query['offset']
|
||||
delete query['date_from']
|
||||
delete query['date_to']
|
||||
return query
|
||||
},
|
||||
tableHasQuery() {
|
||||
return Object.keys(this.tableQuery()).length > 0
|
||||
},
|
||||
defaultHandleExport({ selectedRows }) {
|
||||
this.selectedRows = selectedRows
|
||||
this.dialogStatus = 'export'
|
||||
if (!this.needMFAVerify) {
|
||||
this.showMFADialog = false
|
||||
this.showExportDialog = true
|
||||
} else {
|
||||
this.showMFADialog = true
|
||||
}
|
||||
},
|
||||
downloadCsv(url) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
},
|
||||
async performExport(selectRows, exportOption, q) {
|
||||
const url = `/api/v1/assets/asset-user-auth-infos/`
|
||||
const query = Object.assign({}, q)
|
||||
if (exportOption === 'selected') {
|
||||
const resources = []
|
||||
const data = selectRows
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
resources.push(data[index].id)
|
||||
}
|
||||
const spm = await createSourceIdCache(resources)
|
||||
query['spm'] = spm.spm
|
||||
} else if (exportOption === 'filtered') {
|
||||
// console.log(listTableRef)
|
||||
// console.log(listTableRef.dataTable)
|
||||
// delete query['limit']
|
||||
// delete query['offset']
|
||||
}
|
||||
query['format'] = this.exportTypeOption
|
||||
const queryStr =
|
||||
(url.indexOf('?') > -1 ? '&' : '?') +
|
||||
queryUtil.stringify(query, '=', '&')
|
||||
return this.downloadCsv(url + queryStr)
|
||||
},
|
||||
async performExportConfirm() {
|
||||
const listTableRef = this.$refs.ListTable
|
||||
const query = listTableRef.dataTable.getQuery()
|
||||
delete query['limit']
|
||||
delete query['offset']
|
||||
return this.performExport(this.selectedRows, this.exportOption, query)
|
||||
},
|
||||
async handleExportConfirm() {
|
||||
await this.performExportConfirm()
|
||||
this.showExportDialog = false
|
||||
},
|
||||
handleExportCancel() {
|
||||
this.showExportDialog = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.export-item {
|
||||
width: 100%;
|
||||
display: block;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.export-form >>> .el-form-item__label {
|
||||
line-height: 2
|
||||
}
|
||||
</style>
|
||||
@@ -9,7 +9,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DataForm from '@/components/DataForm'
|
||||
import { DataForm } from '@/components'
|
||||
|
||||
export default {
|
||||
name: 'NestedField',
|
||||
@@ -35,7 +35,7 @@ export default {
|
||||
kwargs: {
|
||||
hasReset: false,
|
||||
hasSaveContinue: false,
|
||||
hasButtons: false
|
||||
defaultButton: false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
<template>
|
||||
<DataForm ref="dataForm" v-loading="loading" :fields="totalFields" :form="iForm" v-bind="$attrs" v-on="$listeners">
|
||||
<FormGroupHeader
|
||||
v-for="(group, i) in groups"
|
||||
:slot="'id:'+group.name"
|
||||
:key="'group-'+group.name"
|
||||
:group="group"
|
||||
:index="i"
|
||||
:line="i !== 0"
|
||||
/>
|
||||
<FormGroupHeader v-for="(group, i) in groups" :slot="'id:'+group.name" :key="'group-'+group.name" :title="group.title" :line="i !== 0" />
|
||||
</DataForm>
|
||||
</template>
|
||||
|
||||
@@ -51,8 +44,7 @@ export default {
|
||||
totalFields: [],
|
||||
loading: true,
|
||||
groups: [],
|
||||
iForm: this.form,
|
||||
errors: {}
|
||||
iForm: this.form
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -33,11 +33,11 @@ export class FormFieldGenerator {
|
||||
break
|
||||
case 'string':
|
||||
type = 'input'
|
||||
if (!fieldRemoteMeta['max_length']) {
|
||||
if (!fieldRemoteMeta.max_length) {
|
||||
field.el.type = 'textarea'
|
||||
field.el.rows = 3
|
||||
}
|
||||
if (fieldRemoteMeta['write_only']) {
|
||||
if (fieldRemoteMeta.write_only) {
|
||||
field.el.type = 'password'
|
||||
}
|
||||
break
|
||||
@@ -132,8 +132,7 @@ export class FormFieldGenerator {
|
||||
this.groups.push({
|
||||
id: groupTitle,
|
||||
title: groupTitle,
|
||||
name: fields[0],
|
||||
fields: fields
|
||||
name: fields[0]
|
||||
})
|
||||
return this.generateFields(fields, fieldsMeta, remoteFieldsMeta)
|
||||
}
|
||||
@@ -147,9 +146,7 @@ export class FormFieldGenerator {
|
||||
field = this.generateField(field, fieldsMeta, remoteFieldsMeta)
|
||||
fields.push(field)
|
||||
} else if (field instanceof Object) {
|
||||
if (this.errors) {
|
||||
this.errors[field.prop] = ''
|
||||
}
|
||||
this.errors[field.prop] = ''
|
||||
fields.push(field)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,12 +170,12 @@ export default {
|
||||
col.filters = column.choices.map(item => {
|
||||
if (typeof (item.value) === 'boolean') {
|
||||
if (item.value) {
|
||||
return { text: item['display_name'], value: 'True' }
|
||||
return { text: item.display_name, value: 'True' }
|
||||
} else {
|
||||
return { text: item['display_name'], value: 'False' }
|
||||
return { text: item.display_name, value: 'False' }
|
||||
}
|
||||
}
|
||||
return { text: item['display_name'], value: item.value }
|
||||
return { text: item.display_name, value: item.value }
|
||||
})
|
||||
col.sortable = false
|
||||
col['column-key'] = col.prop
|
||||
@@ -223,7 +223,7 @@ export default {
|
||||
defaultColumnsNames = totalColumnsNames.filter(n => defaultColumnsNames.indexOf(n) > -1)
|
||||
|
||||
// 最小列
|
||||
const minColumnsNames = _.get(this.iConfig, 'columnsShow.min', ['actions', 'id'])
|
||||
const minColumnsNames = _.get(this.iConfig, 'columnsShow.min', ['action', 'id'])
|
||||
.filter(n => defaultColumnsNames.indexOf(n) > -1)
|
||||
|
||||
// 应该显示的列
|
||||
|
||||
@@ -40,7 +40,7 @@ export default {
|
||||
autoParam: ['id=key', 'name=n', 'level=lv'],
|
||||
type: 'get',
|
||||
headers: {
|
||||
'X-JMS-ORG': this.$store.getters.currentOrg ? this.$store.getters.currentOrg.id : ''
|
||||
'X-JMS-ORG': JSON.parse(this.$cookie.get('jms_current_org')) ? JSON.parse(this.$cookie.get('jms_current_org')).id : ''
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
@@ -89,7 +89,7 @@ export default {
|
||||
return
|
||||
}
|
||||
if (currentNode) {
|
||||
currentNode.name = currentNode.meta.data.value
|
||||
currentNode.name = currentNode.meta.node.value
|
||||
}
|
||||
this.zTree.editName(currentNode)
|
||||
},
|
||||
@@ -108,12 +108,12 @@ export default {
|
||||
const query = Object.assign({}, this.$route.query)
|
||||
if (treeNode.meta.type === 'node') {
|
||||
this.currentNode = treeNode
|
||||
this.currentNodeId = treeNode.meta.data.id
|
||||
this.currentNodeId = treeNode.meta.node.id
|
||||
query['node'] = this.currentNodeId
|
||||
url = `${this.setting.url}${combinator}node_id=${treeNode.meta.data.id}&show_current_asset=${show_current_asset}`
|
||||
url = `${this.setting.url}${combinator}node_id=${treeNode.meta.node.id}&show_current_asset=${show_current_asset}`
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
query['asset'] = treeNode.meta.data.id
|
||||
url = `${this.setting.url}${combinator}asset_id=${treeNode.meta.data.id}&show_current_asset=${show_current_asset}`
|
||||
query['asset'] = treeNode.meta.asset.id
|
||||
url = `${this.setting.url}${combinator}asset_id=${treeNode.meta.asset.id}&show_current_asset=${show_current_asset}`
|
||||
}
|
||||
this.$router.push({ query })
|
||||
this.$emit('urlChange', url)
|
||||
@@ -125,7 +125,7 @@ export default {
|
||||
return
|
||||
}
|
||||
this.$axios.delete(
|
||||
`${this.treeSetting.nodeUrl}${currentNode.meta.data.id}/`
|
||||
`${this.treeSetting.nodeUrl}${currentNode.meta.node.id}/`
|
||||
).then(() => {
|
||||
this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
this.zTree.removeNode(currentNode)
|
||||
@@ -143,7 +143,7 @@ export default {
|
||||
url,
|
||||
{ 'value': treeNode.name }
|
||||
).then(res => {
|
||||
let assetsAmount = treeNode.meta.data.assetsAmount
|
||||
let assetsAmount = treeNode.meta.node.assetsAmount
|
||||
if (!assetsAmount) {
|
||||
assetsAmount = 0
|
||||
}
|
||||
@@ -208,9 +208,9 @@ export default {
|
||||
onDrop: function(event, treeId, treeNodes, targetNode, moveType) {
|
||||
const treeNodesIds = []
|
||||
$.each(treeNodes, function(index, value) {
|
||||
treeNodesIds.push(value.meta.data.id)
|
||||
treeNodesIds.push(value.meta.node.id)
|
||||
})
|
||||
const theUrl = `${this.treeSetting.nodeUrl}${targetNode.meta.data.id}/children/add/`
|
||||
const theUrl = `${this.treeSetting.nodeUrl}${targetNode.meta.node.id}/children/add/`
|
||||
this.$axios.put(
|
||||
theUrl, {
|
||||
nodes: treeNodesIds
|
||||
@@ -229,21 +229,21 @@ export default {
|
||||
}
|
||||
this.zTree.expandNode(parentNode, true, false, true, false)
|
||||
// http://localhost/api/v1/assets/nodes/85aa4ee2-0bd9-41db-9079-aa3646448d0c/children/
|
||||
const url = `${this.treeSetting.nodeUrl}${parentNode.meta.data.id}/children/`
|
||||
const url = `${this.treeSetting.nodeUrl}${parentNode.meta.node.id}/children/`
|
||||
this.$axios.post(url, {}).then(data => {
|
||||
const newNode = {
|
||||
id: data['key'],
|
||||
name: data['value'],
|
||||
pId: parentNode.id,
|
||||
meta: {
|
||||
data: data
|
||||
'node': data
|
||||
}
|
||||
}
|
||||
newNode.checked = this.zTree.getSelectedNodes()[0].checked
|
||||
this.zTree.addNodes(parentNode, 0, newNode)
|
||||
// vm.$refs.dataztree.refresh()
|
||||
const node = this.zTree.getNodeByParam('id', newNode.id, parentNode)
|
||||
this.currentNodeId = node.meta.data.id || newNode.id
|
||||
this.currentNodeId = node.meta.node.id || newNode.id
|
||||
this.zTree.editName(node)
|
||||
this.$message.success(this.$t('common.createSuccessMsg'))
|
||||
}).catch(error => {
|
||||
|
||||
@@ -97,7 +97,6 @@ export default {
|
||||
}
|
||||
},
|
||||
props: {
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
data: Object,
|
||||
prop: {
|
||||
type: String,
|
||||
@@ -105,13 +104,10 @@ export default {
|
||||
return this.data.id
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types,vue/require-default-prop
|
||||
itemValue: {},
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
value: Object,
|
||||
disabled: Boolean,
|
||||
readonly: Boolean,
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
options: Array
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-form ref="elForm" v-bind="$attrs" :model="value" class="el-form-renderer">
|
||||
<template v-for="item in innerContent">
|
||||
<slot v-if="!isHidden(item)" :name="`id:${item.id}`" />
|
||||
<slot :name="`id:${item.id}`" />
|
||||
<component
|
||||
:is="item.type === GROUP ? 'render-form-group' : 'render-form-item'"
|
||||
:key="item.id"
|
||||
@@ -13,7 +13,7 @@
|
||||
:options="options[item.id]"
|
||||
@updateValue="updateValue"
|
||||
/>
|
||||
<slot v-if="!isHidden(item)" :name="`$id:${item.id}`" />
|
||||
<slot :name="`$id:${item.id}`" />
|
||||
</template>
|
||||
<slot />
|
||||
</el-form>
|
||||
@@ -202,18 +202,6 @@ export default {
|
||||
setOptions(id, options) {
|
||||
_set(this.options, id, options)
|
||||
this.options = { ...this.options } // 设置之前不存在的 options 时需要重新设置响应式更新
|
||||
},
|
||||
isHidden(item) {
|
||||
if (!item.el || !item.el['hiddenGroup']) {
|
||||
return false
|
||||
}
|
||||
if (item.hidden === true) {
|
||||
return true
|
||||
}
|
||||
if (typeof item.hidden === 'function') {
|
||||
return item.hidden(this.value)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<slot v-for="item in fields" :slot="`id:${item.id}`" :name="`id:${item.id}`" />
|
||||
<slot v-for="item in fields" :slot="`$id:${item.id}`" :name="`$id:${item.id}`" />
|
||||
|
||||
<el-form-item v-if="hasButtons" class="form-buttons">
|
||||
<el-form-item>
|
||||
<el-button v-for="button in moreButtons" :key="button.title" size="small" v-bind="button" @click="handleClick(button)">{{ button.title }}</el-button>
|
||||
<el-button v-if="defaultButton && hasReset" size="small" @click="resetForm('form')">{{ $t('common.Reset') }}</el-button>
|
||||
<el-button v-if="defaultButton && hasSaveContinue" size="small" @click="submitForm('form', true)">{{ $t('common.SaveAndAddAnother') }}</el-button>
|
||||
@@ -32,10 +32,6 @@ export default {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasButtons: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasReset: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
|
||||
@@ -840,7 +840,7 @@ export default {
|
||||
this.$emit('selection-change', val)
|
||||
},
|
||||
totalData(val) {
|
||||
if (val && val.length !== this.total) {
|
||||
if (val) {
|
||||
this.page = defaultFirstPage
|
||||
this.total = val.length
|
||||
this.getList()
|
||||
|
||||
@@ -94,12 +94,7 @@ export default {
|
||||
tableConfig() {
|
||||
const tableDefaultConfig = this.defaultConfig
|
||||
tableDefaultConfig.paginationSize = _.get(this.globalTableConfig, 'paginationSize', 15)
|
||||
let tableAttrs = tableDefaultConfig.tableAttrs
|
||||
if (this.config.tableAttrs) {
|
||||
tableAttrs = Object.assign(tableAttrs, this.config.tableAttrs)
|
||||
}
|
||||
const config = Object.assign(tableDefaultConfig, this.config)
|
||||
config.tableAttrs = tableAttrs
|
||||
return config
|
||||
},
|
||||
iListeners() {
|
||||
|
||||
@@ -28,20 +28,13 @@ export default {
|
||||
return this.formatter(this.item, this.value)
|
||||
}
|
||||
if (typeof this.value === 'boolean') {
|
||||
return (
|
||||
<span class='item-value'>{this.toChoicesDisplay(this.value)}</span>
|
||||
)
|
||||
return <span>{this.toChoicesDisplay(this.value)}</span>
|
||||
}
|
||||
return (
|
||||
<span class='item-value'>{this.value}</span>
|
||||
)
|
||||
return <span>{this.value}</span>
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-value {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
<el-select
|
||||
ref="select"
|
||||
v-model="iValue"
|
||||
v-loading="!initialized"
|
||||
v-loadmore="loadMore"
|
||||
:options="iOptions"
|
||||
:remote="remote"
|
||||
:remote-method="filterOptions"
|
||||
:multiple="multiple"
|
||||
:clearable="clearable"
|
||||
filterable
|
||||
:clearable="clearable"
|
||||
popper-append-to-body
|
||||
class="select2"
|
||||
v-bind="$attrs"
|
||||
@@ -98,6 +97,7 @@ export default {
|
||||
return {
|
||||
loading: false,
|
||||
initialized: false,
|
||||
iValue: this.value ? this.value : [],
|
||||
defaultParams: _.cloneDeep(defaultParams),
|
||||
params: _.cloneDeep(defaultParams),
|
||||
iOptions: this.options || [],
|
||||
@@ -112,18 +112,6 @@ export default {
|
||||
optionsValues() {
|
||||
return this.iOptions.map((v) => v.value)
|
||||
},
|
||||
iValue: {
|
||||
set(val) {
|
||||
const noValue = !this.value || this.value.length === 0
|
||||
if (noValue && !this.initialized) {
|
||||
return
|
||||
}
|
||||
this.$emit('input', val)
|
||||
},
|
||||
get() {
|
||||
return this.value
|
||||
}
|
||||
},
|
||||
iAjax() {
|
||||
const defaultPageSize = 10
|
||||
const defaultMakeParams = (params) => {
|
||||
@@ -173,14 +161,11 @@ export default {
|
||||
this.iValue = iNew
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
mounted() {
|
||||
// this.$log.debug('Select2 url is: ', this.iAjax.url)
|
||||
if (!this.initialized) {
|
||||
await this.initialSelect()
|
||||
setTimeout(() => {
|
||||
this.initialized = true
|
||||
this.iValue = this.value
|
||||
})
|
||||
this.initialSelect()
|
||||
this.initialized = true
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
// 因为elform存在问题,这个来清楚验证
|
||||
@@ -258,13 +243,9 @@ export default {
|
||||
// this.$log.debug('Select ajax config', this.iAjax)
|
||||
if (this.iAjax.url) {
|
||||
if (this.value && this.value.length !== 0) {
|
||||
this.$log.debug('Start init select2 value, ', this.value)
|
||||
let value = this.value
|
||||
if (!Array.isArray(value)) {
|
||||
value = [value]
|
||||
}
|
||||
const data = await createSourceIdCache(value)
|
||||
this.params.spm = data['spm']
|
||||
this.$log.debug('Start init select2 value')
|
||||
const data = await createSourceIdCache(this.value)
|
||||
this.params.spm = data.spm
|
||||
await this.getInitialOptions()
|
||||
}
|
||||
await this.getOptions()
|
||||
|
||||
@@ -8,17 +8,13 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// value: {
|
||||
// type: String,
|
||||
// default: () => ''
|
||||
// },
|
||||
tip: {
|
||||
value: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
},
|
||||
toFormat: {
|
||||
tip: {
|
||||
type: String,
|
||||
default: () => 'string'
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -29,11 +25,7 @@ export default {
|
||||
const vm = this
|
||||
const reader = new FileReader()
|
||||
reader.onload = function() {
|
||||
let result = this.result
|
||||
if (vm.toFormat === 'object') {
|
||||
result = JSON.parse(result)
|
||||
}
|
||||
vm.$emit('input', result)
|
||||
vm.$emit('input', this.result)
|
||||
}
|
||||
reader.readAsText(
|
||||
e.target.files[0]
|
||||
|
||||
@@ -22,12 +22,8 @@ export default {
|
||||
}
|
||||
},
|
||||
rules(item) {
|
||||
let userIsOrgAdmin = item.el.userIsOrgAdmin
|
||||
// undefined 个人信息更新或用户更改密码页面,使用当前用户;否则使用更新用户表单中传递的值
|
||||
userIsOrgAdmin = userIsOrgAdmin === undefined ? store.getters.currentUserIsAdmin : userIsOrgAdmin
|
||||
|
||||
const passwordRule = store.getters.publicSettings.PASSWORD_RULE
|
||||
const validatePassword = function(rule, value, callback) {
|
||||
const validatePassword = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
return callback()
|
||||
}
|
||||
@@ -50,10 +46,7 @@ export default {
|
||||
return callback(new Error(msg))
|
||||
}
|
||||
}
|
||||
let secureLength = passwordRule ? passwordRule.SECURITY_PASSWORD_MIN_LENGTH : 7
|
||||
if (userIsOrgAdmin) {
|
||||
secureLength = passwordRule ? passwordRule.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH : 7
|
||||
}
|
||||
const secureLength = passwordRule ? passwordRule.SECURITY_PASSWORD_MIN_LENGTH : 7
|
||||
if (value.length < secureLength) {
|
||||
return callback(new Error(i18n.t('common.password.MIN_LENGTH_ERROR', [secureLength])))
|
||||
}
|
||||
@@ -66,12 +59,17 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
attrs: {
|
||||
secureLength: 7
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['publicSettings'])
|
||||
},
|
||||
created() {
|
||||
const passwordRule = this.publicSettings.PASSWORD_RULE || {}
|
||||
this.attrs.secureLength = passwordRule ? passwordRule.SECURITY_PASSWORD_MIN_LENGTH : 7
|
||||
},
|
||||
methods: {
|
||||
handleInput(value) {
|
||||
this.$emit('input', value)
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
<template>
|
||||
<div class="form-group-header">
|
||||
<div v-if="line" class="hr-line-dashed" />
|
||||
<h3>{{ group.title }}</h3>
|
||||
<h3>{{ title }}</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Title'
|
||||
},
|
||||
line: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
group: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
vm.tableConfig.initialUrl = vm.tableConfig.url
|
||||
}
|
||||
const initialUrl = vm.tableConfig.initialUrl
|
||||
const nodeId = node.meta.data.id
|
||||
const nodeId = node.meta.node.id
|
||||
const url = initialUrl.replace('/assets/', `/nodes/${nodeId}/assets/`)
|
||||
vm.tableConfig.url = url
|
||||
}
|
||||
|
||||
@@ -1,45 +1,29 @@
|
||||
<template>
|
||||
<div>
|
||||
<MFAVerifyDialog
|
||||
v-if="mfaDialogShow"
|
||||
@MFAVerifyDone="showExportDialog"
|
||||
@MFAVerifyCancel="handleExportCancel"
|
||||
/>
|
||||
<Dialog
|
||||
v-if="exportDialogShow"
|
||||
:title="$t('common.Export')"
|
||||
:visible.sync="exportDialogShow"
|
||||
:destroy-on-close="true"
|
||||
@confirm="handleExportConfirm()"
|
||||
@cancel="handleExportCancel()"
|
||||
>
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportTypeOption">
|
||||
<el-radio v-for="option of exportTypeOptions" :key="option.value" style="padding: 10px 20px;" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item class="export-form" :label="this.$t('common.imExport.ExportRange')" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportOption">
|
||||
<el-radio v-for="option of exportOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
</div>
|
||||
<Dialog v-if="showExportDialog" :title="$t('common.Export')" :visible.sync="showExportDialog" :destroy-on-close="true" @confirm="handleExportConfirm()" @cancel="handleExportCancel()">
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportTypeOption">
|
||||
<el-radio v-for="option of exportTypeOptions" :key="option.value" style="padding: 10px 20px;" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item class="export-form" :label="this.$t('common.imExport.ExportRange')" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportOption">
|
||||
<el-radio v-for="option of exportOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
|
||||
import { createSourceIdCache } from '@/api/common'
|
||||
import * as queryUtil from '@/components/DataTable/compenents/el-data-table/utils/query'
|
||||
|
||||
export default {
|
||||
name: 'ExportDialog',
|
||||
components: {
|
||||
Dialog,
|
||||
MFAVerifyDialog
|
||||
Dialog
|
||||
},
|
||||
props: {
|
||||
selectedRows: {
|
||||
@@ -48,20 +32,12 @@ export default {
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
beforeExport: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
},
|
||||
mfaVerifyRequired: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: () => ''
|
||||
},
|
||||
performExport: {
|
||||
type: Function,
|
||||
default(selectedRows, exportOptions, query, exportType) {
|
||||
return this.defaultPerformExport(selectedRows, exportOptions, query, exportType)
|
||||
default(selectedRows, exportOptions, query) {
|
||||
return this.defaultPerformExport(selectedRows, exportOptions, query)
|
||||
}
|
||||
},
|
||||
canExportAll: {
|
||||
@@ -79,12 +55,10 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
exportDialogShow: false,
|
||||
showExportDialog: false,
|
||||
exportOption: 'all',
|
||||
exportTypeOption: 'csv',
|
||||
meta: {},
|
||||
mfaVerified: false,
|
||||
mfaDialogShow: false
|
||||
meta: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -141,33 +115,20 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$eventBus.$on('showExportDialog', ({ selectedRows, url, name }) => {
|
||||
// Todo: 没有时间了,只能先这么处理了
|
||||
if (url === this.url || url.indexOf(this.url) > -1 || url.indexOf('account') > -1) {
|
||||
this.showExportDialog()
|
||||
this.$eventBus.$on('showExportDialog', ({ selectedRows, url }) => {
|
||||
if (url === this.url) {
|
||||
this.showExportDialog = true
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
showExportDialog() {
|
||||
if (!this.mfaVerifyRequired) {
|
||||
this.exportDialogShow = true
|
||||
return
|
||||
}
|
||||
// 这是需要校验 MFA 的
|
||||
if (!this.mfaDialogShow) {
|
||||
this.mfaDialogShow = true
|
||||
} else {
|
||||
this.exportDialogShow = true
|
||||
}
|
||||
},
|
||||
downloadCsv(url) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
},
|
||||
async defaultPerformExport(selectRows, exportOption, q, exportTypeOption) {
|
||||
async defaultPerformExport(selectRows, exportOption, q) {
|
||||
const url = (process.env.VUE_APP_ENV === 'production') ? (`${this.url}`) : (`${process.env.VUE_APP_BASE_API}${this.url}`)
|
||||
const query = Object.assign({}, q)
|
||||
if (exportOption === 'selected') {
|
||||
@@ -178,8 +139,13 @@ export default {
|
||||
}
|
||||
const spm = await createSourceIdCache(resources)
|
||||
query['spm'] = spm.spm
|
||||
} else if (exportOption === 'filtered') {
|
||||
// console.log(listTableRef)
|
||||
// console.log(listTableRef.dataTable)
|
||||
// delete query['limit']
|
||||
// delete query['offset']
|
||||
}
|
||||
query['format'] = exportTypeOption
|
||||
query['format'] = this.exportTypeOption
|
||||
const queryStr =
|
||||
(url.indexOf('?') > -1 ? '&' : '?') +
|
||||
queryUtil.stringify(query, '=', '&')
|
||||
@@ -187,20 +153,17 @@ export default {
|
||||
},
|
||||
async handleExport() {
|
||||
const listTableRef = this.$parent.$parent.$parent.$parent
|
||||
const query = listTableRef['dataTable'].getQuery()
|
||||
const query = listTableRef.dataTable.getQuery()
|
||||
delete query['limit']
|
||||
delete query['offset']
|
||||
await this.beforeExport()
|
||||
return this.performExport(this.selectedRows, this.exportOption, query, this.exportTypeOption)
|
||||
return this.performExport(this.selectedRows, this.exportOption, query)
|
||||
},
|
||||
async handleExportConfirm() {
|
||||
await this.handleExport()
|
||||
this.exportDialogShow = false
|
||||
this.mfaDialogShow = false
|
||||
this.showExportDialog = false
|
||||
},
|
||||
handleExportCancel() {
|
||||
this.exportDialogShow = false
|
||||
this.mfaDialogShow = false
|
||||
this.showExportDialog = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<ExportDialog :selected-rows="selectedRows" v-bind="exportOptions" v-on="$listeners" />
|
||||
<ImportDialog :selected-rows="selectedRows" v-bind="importOptions" v-on="$listeners" />
|
||||
<ExportDialog :selected-rows="selectedRows" :url="url" v-bind="$attrs" v-on="$listeners" />
|
||||
<ImportDialog :selected-rows="selectedRows" :url="url" v-bind="$attrs" v-on="$listeners" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -10,7 +10,7 @@ import ExportDialog from './ExportDialog'
|
||||
import ImportDialog from './ImportDialog'
|
||||
|
||||
export default {
|
||||
name: 'ImExportDialog',
|
||||
name: 'DialogAction',
|
||||
components: {
|
||||
ExportDialog,
|
||||
ImportDialog
|
||||
@@ -20,13 +20,9 @@ export default {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
exportOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
importOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
url: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<script>
|
||||
import DataTable from '@/components/DataTable'
|
||||
import { sleep, getUpdateObjURL } from '@/utils/common'
|
||||
import { sleep } from '@/utils/common'
|
||||
import { EditableInputFormatter, StatusFormatter } from '@/components/TableFormatters'
|
||||
export default {
|
||||
name: 'ImportTable',
|
||||
@@ -350,7 +350,7 @@ export default {
|
||||
}
|
||||
},
|
||||
async performUpdateObject(item) {
|
||||
const updateUrl = getUpdateObjURL(this.url, item.id)
|
||||
const updateUrl = `${this.url}${item.id}/`
|
||||
return this.$axios.put(
|
||||
updateUrl,
|
||||
item,
|
||||
@@ -421,7 +421,6 @@ export default {
|
||||
.importTable >>> .cell {
|
||||
min-height: 20px;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -24,16 +24,6 @@ export default {
|
||||
hasLeftActions: defaultTrue,
|
||||
hasCreate: defaultTrue,
|
||||
canCreate: defaultTrue,
|
||||
createRoute: {
|
||||
type: [String, Object, Function],
|
||||
default: function() {
|
||||
return this.$route.name.replace('List', 'Create')
|
||||
}
|
||||
},
|
||||
createInNewPage: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hasBulkDelete: defaultTrue,
|
||||
hasBulkUpdate: defaultFalse,
|
||||
hasMoreActions: defaultTrue,
|
||||
@@ -41,6 +31,12 @@ export default {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
createRoute: {
|
||||
type: [String, Object, Function],
|
||||
default: function() {
|
||||
return this.$route.name.replace('List', 'Create')
|
||||
}
|
||||
},
|
||||
reloadTable: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
@@ -162,13 +158,8 @@ export default {
|
||||
} else if (typeof this.createRoute === 'object') {
|
||||
route = this.createRoute
|
||||
}
|
||||
this.$router.push(route)
|
||||
this.$log.debug('handle create')
|
||||
if (this.createInNewPage) {
|
||||
const { href } = this.$router.resolve(route)
|
||||
window.open(href, '_blank')
|
||||
} else {
|
||||
this.$router.push(route)
|
||||
}
|
||||
},
|
||||
defaultBulkDeleteCallback({ selectedRows, reloadTable }) {
|
||||
const msg = this.$t('common.deleteWarningMsg') + ' ' + selectedRows.length + ' ' + this.$t('common.rows') + ' ?'
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<ActionsGroup :is-fa="true" :actions="rightSideActions" class="right-side-actions right-side-item" />
|
||||
<ImExportDialog
|
||||
:selected-rows="selectedRows"
|
||||
:export-options="iExportOptions"
|
||||
:import-options="iImportOptions"
|
||||
v-bind="$attrs"
|
||||
/>
|
||||
<ActionsGroup :is-fa="true" :actions="rightSideActions" :url="tableUrl" class="right-side-actions right-side-item" />
|
||||
<ImExportDialog :selected-rows="selectedRows" :url="tableUrl" v-bind="$attrs" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -14,7 +9,6 @@
|
||||
import ActionsGroup from '@/components/ActionsGroup'
|
||||
import ImExportDialog from './ImExportDialog'
|
||||
import { cleanActions } from './utils'
|
||||
import { assignIfNot } from '@/utils/common'
|
||||
|
||||
const defaultTrue = { type: Boolean, default: true }
|
||||
|
||||
@@ -30,41 +24,27 @@ export default {
|
||||
default: ''
|
||||
},
|
||||
hasExport: defaultTrue,
|
||||
exportOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
handleExportClick: {
|
||||
handleExport: {
|
||||
type: Function,
|
||||
default: function({ selectedRows }) {
|
||||
this.$eventBus.$emit('showExportDialog', { selectedRows, url: this.tableUrl, name: this.name })
|
||||
this.$eventBus.$emit('showExportDialog', { selectedRows, url: this.tableUrl })
|
||||
}
|
||||
},
|
||||
hasImport: defaultTrue,
|
||||
importOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
handleImportClick: {
|
||||
handleImport: {
|
||||
type: Function,
|
||||
default: function({ selectedRows }) {
|
||||
this.$eventBus.$emit('showImportDialog', { selectedRows, url: this.tableUrl, name: this.name })
|
||||
this.$eventBus.$emit('showImportDialog', { selectedRows, url: this.tableUrl })
|
||||
}
|
||||
},
|
||||
hasColumnSetting: defaultTrue,
|
||||
handleTableSettingClick: {
|
||||
handleColumnConfig: {
|
||||
type: Function,
|
||||
default: function({ selectedRows }) {
|
||||
this.$eventBus.$emit('showColumnSettingPopover', { url: this.tableUrl, row: selectedRows, name: this.name })
|
||||
this.$eventBus.$emit('showColumnSettingPopover', { url: this.tableUrl })
|
||||
}
|
||||
},
|
||||
hasRefresh: defaultTrue,
|
||||
handleRefreshClick: {
|
||||
type: Function,
|
||||
default: function() {
|
||||
this.reloadTable()
|
||||
}
|
||||
},
|
||||
selectedRows: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
@@ -81,12 +61,13 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
defaultRightSideActions: [
|
||||
{ name: 'actionColumnSetting', fa: 'fa-cog', tip: this.$t('common.CustomCol'), has: this.hasColumnSetting, callback: this.handleTableSettingClick.bind(this) },
|
||||
{ name: 'actionImport', fa: 'fa-upload', tip: this.$t('common.Import'), has: this.hasImport, callback: this.handleImportClick.bind(this) },
|
||||
{ name: 'actionExport', fa: 'fa-download', tip: this.$t('common.Export'), has: this.hasExport, callback: this.handleExportClick.bind(this) },
|
||||
{ name: 'actionRefresh', fa: 'fa-refresh', tip: this.$t('common.Refresh'), has: this.hasRefresh, callback: this.handleRefreshClick.bind(this) }
|
||||
{ name: 'actionColumnSetting', fa: 'fa-cog', tip: this.$t('common.CustomCol'), has: this.hasColumnSetting, callback: this.handleColumnConfig.bind(this) },
|
||||
{ name: 'actionExport', fa: 'fa-download', tip: this.$t('common.Export'), has: this.hasExport, callback: this.handleExport.bind(this) },
|
||||
{ name: 'actionImport', fa: 'fa-upload', tip: this.$t('common.Import'), has: this.hasImport, callback: this.handleImport.bind(this) },
|
||||
{ name: 'actionRefresh', fa: 'fa-refresh', tip: this.$t('common.Refresh'), has: this.hasRefresh, callback: this.handleRefresh }
|
||||
],
|
||||
dialogExportVisible: false
|
||||
dialogExportVisible: false,
|
||||
exportValue: 2
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -100,18 +81,20 @@ export default {
|
||||
},
|
||||
hasSelectedRows() {
|
||||
return this.selectedRows.length > 0
|
||||
},
|
||||
iImportOptions() {
|
||||
return assignIfNot(this.importOptions, { url: this.tableUrl })
|
||||
},
|
||||
iExportOptions() {
|
||||
const options = assignIfNot(this.exportOptions, { url: this.tableUrl })
|
||||
return options
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleTagSearch(val) {
|
||||
this.searchTable(val)
|
||||
},
|
||||
// handleExport({ selectedRows }) {
|
||||
// this.$eventBus.$emit('showExportDialog', { selectedRows })
|
||||
// },
|
||||
// handleImport({ selectedRows }) {
|
||||
// this.$eventBus.$emit('showImportDialog', { selectedRows })
|
||||
// },
|
||||
handleRefresh() {
|
||||
this.reloadTable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<TableAction
|
||||
:table-url="tableUrl"
|
||||
:search-table="search"
|
||||
:date-pick="handleDateChange"
|
||||
:selected-rows="selectedRows"
|
||||
:reload-table="reloadTable"
|
||||
v-bind="headerActions"
|
||||
/>
|
||||
<TableAction :table-url="iTableConfig.url" :search-table="search" :date-pick="handleDateChange" v-bind="headerActions" :selected-rows="selectedRows" :reload-table="reloadTable" />
|
||||
<IBox class="table-content">
|
||||
<AutoDataTable
|
||||
ref="dataTable"
|
||||
:filter-table="filter"
|
||||
:config="iTableConfig"
|
||||
@selection-change="handleSelectionChange"
|
||||
v-on="$listeners"
|
||||
/>
|
||||
<AutoDataTable ref="dataTable" :filter-table="filter" :config="iTableConfig" @selection-change="handleSelectionChange" v-on="$listeners" />
|
||||
</IBox>
|
||||
</div>
|
||||
</template>
|
||||
@@ -63,9 +50,6 @@ export default {
|
||||
this.$log.debug('Header actions', this.headerActions)
|
||||
this.$log.debug('ListTable: iTableConfig change', config)
|
||||
return config
|
||||
},
|
||||
tableUrl() {
|
||||
return this.iTableConfig.url
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -129,6 +113,15 @@ export default {
|
||||
& >>> .el-table__header thead > tr > th {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/*& >>> .el-table--striped .el-table__body tr.el-table__row--striped td {*/
|
||||
/*background: white;*/
|
||||
/*}*/
|
||||
|
||||
/*& >>> .el-table th, .el-table tr {*/
|
||||
/*background-color: red;*/
|
||||
/*!*background-color: #FAFAFA;*!*/
|
||||
/*}*/
|
||||
}
|
||||
|
||||
//修改颜色
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<template>
|
||||
<Dialog
|
||||
:title="$t('common.MFAVerify')"
|
||||
:width="'50'"
|
||||
:show-confirm="false"
|
||||
:show-cancel="false"
|
||||
:visible.sync="visible"
|
||||
:destroy-on-close="true"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="4">
|
||||
<div style="line-height: 34px;text-align: center">MFA</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-input v-model="MFAToken" />
|
||||
<span class="help-tips help-block">{{ $t('common.MFARequireForSecurity') }}</span>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="verifyMFA">
|
||||
{{ this.$t('common.Confirm') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
|
||||
export default {
|
||||
name: 'MFAVerifyDialog',
|
||||
components: {
|
||||
Dialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
MFAToken: '',
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (!val) {
|
||||
this.$emit('MFAVerifyCancel', true)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$axios.get('/api/v1/authentication/otp/verify/', { disableFlashErrorMsg: true }).then(() => {
|
||||
this.$emit('MFAVerifyDone', true)
|
||||
}).catch(err => {
|
||||
this.$log.debug('Verify otp code error: ', err)
|
||||
this.visible = true
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
verifyMFA() {
|
||||
if (this.MFAToken.length !== 6) {
|
||||
return this.$message.error(this.$tc('common.MFAErrorMsg'))
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/otp/verify/`, {
|
||||
code: this.MFAToken
|
||||
}
|
||||
).then(res => {
|
||||
this.$emit('MFAVerifyDone', true)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<IBox :fa="fa" :title="title" v-bind="$attrs">
|
||||
<IBox fa="fa-edit" :title="title" v-bind="$attrs">
|
||||
<div v-for="action of actions" :key="action.title" class="quick-actions">
|
||||
<table>
|
||||
<ActionItem v-if="action.has === undefined || action.has" :action="action" />
|
||||
@@ -20,10 +20,6 @@ export default {
|
||||
ActionItem
|
||||
},
|
||||
props: {
|
||||
fa: {
|
||||
type: String,
|
||||
default: () => 'fa-edit'
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default() {
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
<el-card shadow="never">
|
||||
<div slot="header" class="summary-header">
|
||||
<span class="header-title">{{ title }}</span>
|
||||
<span class="pull-right right-side">
|
||||
<slot name="header-right">
|
||||
<el-tag :type="rightSideLabel.type || 'success'" effect="dark" size="mini">{{ rightSideLabel.title }}</el-tag>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
<slot>
|
||||
<h1 class="no-margins">
|
||||
<span v-if="body.disabled" class="disabled-link">{{ body.count }}</span>
|
||||
<router-link v-else :to="body.route">
|
||||
<router-link :to="body.route">
|
||||
<span>{{ body.count }}</span>
|
||||
</router-link>
|
||||
</h1>
|
||||
@@ -70,8 +74,4 @@ export default {
|
||||
.no-margins {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.disabled-link {
|
||||
color: #428bca;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,12 +8,9 @@ import BaseFormatter from './base'
|
||||
|
||||
const defaultPerformDelete = function({ row, col }) {
|
||||
const id = row.id
|
||||
const url = new URL(this.url, location.origin)
|
||||
url.pathname += `${id}/`
|
||||
const deleteUrl = url.href
|
||||
return this.$axios.delete(deleteUrl)
|
||||
const url = `${this.url}${id}/`
|
||||
return this.$axios.delete(url)
|
||||
}
|
||||
|
||||
const defaultUpdateCallback = function({ row, col }) {
|
||||
const id = row.id
|
||||
let route = { params: { id: id }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tooltip v-if="formatterArgs.hasTips" placement="bottom" effect="dark">
|
||||
<div slot="content" v-html="tips" />
|
||||
<div slot="content">{{ tipStatus }}<br>{{ tipTime }}</div>
|
||||
<i :class="'fa ' + iconClass" />
|
||||
</el-tooltip>
|
||||
<i v-else :class="'fa ' + iconClass" />
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<script>
|
||||
import BaseFormatter from './base'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
export default {
|
||||
name: 'ChoicesFormatter',
|
||||
extends: BaseFormatter,
|
||||
@@ -22,12 +23,21 @@ export default {
|
||||
true: 'fa-check text-primary',
|
||||
false: 'fa-times text-danger'
|
||||
},
|
||||
getIconKey({ row, cellValue }) {
|
||||
return cellValue
|
||||
typeChange(val) {
|
||||
return !!val
|
||||
},
|
||||
hasTips: false,
|
||||
getTips: ({ row, cellValue }) => {
|
||||
return cellValue
|
||||
tipStatus(val, vm) {
|
||||
if (!val) {
|
||||
return vm.$t('assets.Unknown')
|
||||
}
|
||||
if (val.status === 0) {
|
||||
return vm.$t('assets.Unreachable')
|
||||
} else if (val.status === 1) {
|
||||
return vm.$t('assets.Reachable')
|
||||
} else if (val.status === 2) {
|
||||
return vm.$t('assets.Unknown')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,11 +50,18 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
iconClass() {
|
||||
const key = this.formatterArgs.getIconKey({ row: this.row, cellValue: this.cellValue })
|
||||
const key = this.formatterArgs.typeChange(this.cellValue)
|
||||
return this.formatterArgs.iconChoices[key]
|
||||
},
|
||||
tips() {
|
||||
return this.formatterArgs.getTips({ cellValue: this.cellValue, row: this.row })
|
||||
tipStatus() {
|
||||
const vm = this
|
||||
return this.formatterArgs.tipStatus(this.cellValue, vm)
|
||||
},
|
||||
tipTime() {
|
||||
if (!this.cellValue) {
|
||||
return ''
|
||||
}
|
||||
return toSafeLocalDateStr(this.cellValue.datetime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
defaultOnDelete(col, row, cellValue, reload) {
|
||||
const url = col.deleteUrl + cellValue
|
||||
this.$axios.delete(url).then(res => {
|
||||
this.$message.success(this.$tc('common.deleteSuccessMsg'))
|
||||
this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
reload()
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.deleteErrorMsg') + ' ' + error)
|
||||
|
||||
@@ -25,16 +25,8 @@ export default {
|
||||
data() {
|
||||
const formatterArgs = Object.assign(this.formatterArgsDefault, this.col.formatterArgs)
|
||||
return {
|
||||
formatterArgs: formatterArgs
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iTitle() {
|
||||
return this.formatterArgs.getTitle({
|
||||
col: this.col,
|
||||
row: this.row,
|
||||
cellValue: this.cellValue
|
||||
})
|
||||
formatterArgs: formatterArgs,
|
||||
iTitle: formatterArgs.getTitle({ col: this.col, row: this.row, cellValue: this.cellValue })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -77,9 +77,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleUrlChange(url) {
|
||||
this.$set(this.iTableConfig, 'url', url)
|
||||
this.$emit('urlChange', url)
|
||||
handleUrlChange(_url) {
|
||||
this.$set(this.iTableConfig, 'url', _url)
|
||||
this.$emit('urlChange', _url)
|
||||
this.forceRerender()
|
||||
},
|
||||
forceRerender() {
|
||||
|
||||
@@ -22,7 +22,5 @@ export { default as QuickActions } from './QuickActions'
|
||||
export { default as Switcher } from './FormFields/Swicher'
|
||||
export { default as SummaryCard } from './SummaryCard'
|
||||
export { default as UploadField } from './FormFields/UploadField'
|
||||
export { default as AccountListTable } from './AccountListTable/index'
|
||||
export { default as AppAccountListTable } from './AppAccountListTable'
|
||||
export { default as AssetUserTable } from './AssetUserTable'
|
||||
export { default as AssetRelationCard } from './AssetRelationCard'
|
||||
export { default as MFAVerifyDialog } from './MFAVerifyDialog'
|
||||
|
||||
@@ -29,12 +29,9 @@
|
||||
},
|
||||
"applications": {
|
||||
"": "",
|
||||
"updateAccountMsg": "请更新系统用户的账号信息",
|
||||
"associateApplication": "关联应用",
|
||||
"RemoteApp": "远程应用",
|
||||
"Database": "数据库",
|
||||
"Cloud": "云",
|
||||
"App": "应用",
|
||||
"applicationsType": {
|
||||
"chrome": "Chrome",
|
||||
"mysql_workbench": "MySQL Workbench",
|
||||
@@ -86,15 +83,11 @@
|
||||
"DBInfo": "数据库信息"
|
||||
},
|
||||
"assets": {
|
||||
"AppList": "应用列表",
|
||||
"AssociateSystemUsers": "关联系统用户",
|
||||
"AssociateAssets": "关联资产",
|
||||
"AssociateNodes": "关联节点",
|
||||
"Action": "动作",
|
||||
"ActiveSelected": "激活所选",
|
||||
"AdminUser": "特权用户",
|
||||
"AdminUser": "管理用户",
|
||||
"AdminUserDetail": "管理用户详情",
|
||||
"AdminUserListHelpMessage": "<b>特权用户</b> 是资产已存在的, 并且拥有 高级权限 的系统用户, 如 root 或 拥有 `NOPASSWD: ALL` sudo 权限的用户。 JumpServer 使用该用户来 `推送系统用户`、`获取资产硬件信息` 等。",
|
||||
"AdminUserListHelpMessage": "管理用户是资产(被控服务器)上的 root,或拥有 NOPASSWD: ALL sudo 权限的用户, JumpServer 使用该用户来 `推送系统用户`、`获取资产硬件信息` 等。\n",
|
||||
"Asset": "资产",
|
||||
"HardwareInfo": "硬件信息",
|
||||
"AssetDetail": "资产详情",
|
||||
@@ -105,11 +98,11 @@
|
||||
"TestGatewayHelpMessage": "如果使用了nat端口映射,请设置为ssh真实监听的端口",
|
||||
"SshPort": "SSH 端口",
|
||||
"AssetNumber": "资产编号",
|
||||
"AssetUserList": "账号列表",
|
||||
"AssetUserList": "资产用户列表",
|
||||
"Assets": "资产",
|
||||
"Auth": "认证",
|
||||
"AccountList": "账号列表",
|
||||
"AutoGenerateKey": "自动生成",
|
||||
"AutoGenerateKey": "自动生成密钥",
|
||||
"AutoPush": "自动推送",
|
||||
"BasePlatform": "基础平台",
|
||||
"Basic": "基本",
|
||||
@@ -122,7 +115,6 @@
|
||||
"CommandFilterRules": "命令过滤器规则",
|
||||
"Comment": "备注",
|
||||
"Cpu": "CPU",
|
||||
"CommonUser": "普通用户",
|
||||
"CreatedBy": "创建者",
|
||||
"Database": "数据库",
|
||||
"DateJoined": "创建日期",
|
||||
@@ -164,11 +156,9 @@
|
||||
"PriorityHelpMessage": "1-100, 1最低优先级,100最高优先级。授权多个用户时,高优先级的系统用户将会作为默认登录用户",
|
||||
"Protocol": "协议",
|
||||
"Protocols": "协议组",
|
||||
"LoginOption": "登录选项",
|
||||
"PublicIp": "公网IP",
|
||||
"Push": "推送",
|
||||
"PushSystemUserNow": "推送系统用户",
|
||||
"PushAllSystemUsersToAsset": "推送所有系统用户到资产",
|
||||
"QuickUpdate": "快速更新",
|
||||
"Reachable": "可连接",
|
||||
"Unreachable": "不可连接",
|
||||
@@ -188,17 +178,15 @@
|
||||
"PasswordHelpMessage": "密码或密钥密码",
|
||||
"SystemUser": "系统用户",
|
||||
"SystemUserDetail": "系统用户详情",
|
||||
"SystemUserListHelpMessage": "<b>系统用户</b> 是JumpServer 登录资产时使用的账号,如 root `ssh root@host`,而不是使用该用户名登录资产(ssh admin@host)`;<br><b>特权用户</b> 是资产已存在的, 并且拥有 高级权限 的系统用户, JumpServer 使用该用户来 `推送系统用户`、`获取资产硬件信息` 等;</br><b>普通用户</b> 可以在资产上预先存在,也可以由 特权用户 来自动创建。",
|
||||
"DynamicUsername": "动态用户名",
|
||||
"SystemUserListHelpMessage": "系统用户是 JumpServer 跳转登录资产时使用的用户,可以理解为登录资产用户,如 web,sa,dba(`ssh web@some-host`),而不是使用某个用户的用户名跳转登录服务器(`ssh xiaoming@some-host`); 简单来说是用户使用自己的用户名登录 JumpServer,JumpServer 使用系统用户登录资产。 系统用户创建时,如果选择了自动推送,JumpServer 会使用 Ansible 自动推送系统用户到资产中,如果资产(交换机)不支持 Ansible,请手动填写账号密码。\n",
|
||||
"SystemUsers": "系统用户",
|
||||
"Test": "测试",
|
||||
"TestAssetsConnective": "测试资产可连接性",
|
||||
"TestAllSystemUsersConnective": "测试所有系统用户可连接性",
|
||||
"TestConnection": "测试连接",
|
||||
"Type": "类型",
|
||||
"UnselectedAssets": "未选择资产或所选择的资产不支持SSH协议连接",
|
||||
"UnselectedNodes": "未选择节点",
|
||||
"UpdateAssetUserToken": "更新账号认证信息",
|
||||
"UpdateAssetUserToken": "更新资产用户认证信息",
|
||||
"Username": "用户名",
|
||||
"UsernameHelpMessage": "用户名是动态的,登录资产时使用当前用户的用户名登录",
|
||||
"Value": "值",
|
||||
@@ -209,7 +197,6 @@
|
||||
"sshKeyFingerprint": "SSH 指纹",
|
||||
"ip": "IP",
|
||||
"sshkey": "sshkey",
|
||||
"SSHKey": "SSH 密钥",
|
||||
"GroupsHelpMessage": "请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)",
|
||||
"HomeHelpMessage": "默认家目录 /home/系统用户名: /home/username",
|
||||
"Home": "家目录",
|
||||
@@ -233,14 +220,6 @@
|
||||
"ReLogin": "重新登录"
|
||||
},
|
||||
"common": {
|
||||
"Logging": "日志记录",
|
||||
"Database": "数据库记录",
|
||||
"Params": "参数",
|
||||
"BasicInfo": "基本信息",
|
||||
"DateUpdated": "更新日期",
|
||||
"ApprovaLevel": "审批信息",
|
||||
"MFAVerify": "验证 MFA",
|
||||
"ViewSecret": "查看密码",
|
||||
"ConnectWebSocketError": "连接 WebSocket 失败",
|
||||
"Action": "动作",
|
||||
"RequestTickets": "申请工单",
|
||||
@@ -259,18 +238,12 @@
|
||||
"bind": "绑定",
|
||||
"unbind": "解绑",
|
||||
"PushSelected":"推送所选",
|
||||
"PushSelectedSystemUsersToAsset": "推送所选系统用户到资产",
|
||||
"TestSelected": "测试所选",
|
||||
"TestSelectedSystemUsersConnective": "测试所选系统用户可连接性",
|
||||
"BadRequestErrorMsg": "请求错误,请检查填写内容",
|
||||
"BadRoleErrorMsg": "请求错误,无该操作权限",
|
||||
"BadConflictErrorMsg": "正在刷新中,请稍后再试",
|
||||
"Basic": "基本",
|
||||
"PleaseAgreeToTheTerms": "请同意条款",
|
||||
"OpenId": "OpenId设置",
|
||||
"Radius": "Radius设置",
|
||||
"Cas": "Cas设置",
|
||||
"other": "其它设置",
|
||||
"BasicInfo": "基本信息",
|
||||
"ApplyInfo": "申请信息",
|
||||
"Cancel": "取消",
|
||||
"Close": "关闭",
|
||||
@@ -536,7 +509,6 @@
|
||||
"downloadFile": "下载文件",
|
||||
"hostName": "主机名",
|
||||
"isValid": "有效",
|
||||
"fromTicket": "来自工单",
|
||||
"isEffective": "起作用的",
|
||||
"nodeCount": "节点数量",
|
||||
"refreshFail": "刷新失败",
|
||||
@@ -551,7 +523,7 @@
|
||||
"systemUserCount": "系统用户数量",
|
||||
"upDownload": "上传下载",
|
||||
"uploadFile": "上传文件",
|
||||
"clipboardCopyPaste":"剪贴板复制粘贴",
|
||||
"clipboardCopyPaste":"复制粘贴",
|
||||
"clipboardCopy":"剪切板复制",
|
||||
"clipboardPaste":"剪切板粘贴",
|
||||
"userCount": "用户数量",
|
||||
@@ -560,14 +532,10 @@
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"TicketFlow": "工单流",
|
||||
"TicketFlowCreate": "创建审批流",
|
||||
"TicketFlowUpdate": "更新审批流",
|
||||
"Accounts": "账号管理",
|
||||
"AssetAccount": "资产账号",
|
||||
"ApplicationAccount": "应用账号",
|
||||
"Ticket":"工单",
|
||||
"SessionDetail": "会话详情",
|
||||
"CommandConfirm": "命令复核",
|
||||
"AdminUserCreate": "创建管理用户",
|
||||
"AdminUserDetail": "管理用户详情",
|
||||
@@ -577,7 +545,6 @@
|
||||
"AssetCreate": "创建资产",
|
||||
"AssetDetail": "资产详情",
|
||||
"AssetList": "资产列表",
|
||||
"Session": "会话",
|
||||
"AssetPermission": "资产授权",
|
||||
"AssetPermissionCreate": "创建资产授权规则",
|
||||
"AssetPermissionDetail": "资产授权详情",
|
||||
@@ -662,7 +629,7 @@
|
||||
"ApplicationPermissionUpdate": "更新应用授权规则",
|
||||
"RemoteAppUpdate": "更新远程应用",
|
||||
"ReplayStorageUpdate": "更新录像存储",
|
||||
"Detail": "详情",
|
||||
"SessionDetail": "会话详情",
|
||||
"SessionOffline": "历史会话",
|
||||
"SessionOnline": "在线会话",
|
||||
"Sessions": "会话管理",
|
||||
@@ -671,7 +638,6 @@
|
||||
"SystemUserDetail": "系统用户详情",
|
||||
"SystemUserList": "系统用户",
|
||||
"SystemUserUpdate": "更新系统用户",
|
||||
"AssetUserList": "资产用户",
|
||||
"TaskDetail": "任务详情",
|
||||
"TaskList": "任务列表",
|
||||
"TaskMonitor": "任务监控",
|
||||
@@ -679,10 +645,6 @@
|
||||
"TicketDetail": "工单详情",
|
||||
"TicketCreate": "创建工单",
|
||||
"Tickets": "工单管理",
|
||||
"Templates": "模版管理",
|
||||
"TemplateDetail": "模版详情",
|
||||
"TemplateCreate": "创建模版",
|
||||
"TemplateUpdate": "更新模版",
|
||||
"UserCreate": "创建用户",
|
||||
"UserDetail": "用户详情",
|
||||
"UserFirstLogin": "首次登录",
|
||||
@@ -701,10 +663,6 @@
|
||||
"SiteMessageList": "站内信"
|
||||
},
|
||||
"sessions": {
|
||||
"SetToDefaultStorage": "设置为默认存储",
|
||||
"SetToDefault": "设为默认",
|
||||
"SetSuccess": "设置成功",
|
||||
"SetFailed": "设置失败",
|
||||
"StorageConfiguration": "存储配置",
|
||||
"accountKey": "账户密钥",
|
||||
"accountName": "账户名称",
|
||||
@@ -714,7 +672,6 @@
|
||||
"target": "目标",
|
||||
"bucket": "桶名称",
|
||||
"command": "命令",
|
||||
"Activity": "活动",
|
||||
"commandStorage": "命令存储",
|
||||
"comment": "备注",
|
||||
"containerName": "容器名称",
|
||||
@@ -778,30 +735,6 @@
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"AlibabaCloud": "阿里云",
|
||||
"TencentCloud": "腾讯云",
|
||||
"Radius": "Radius",
|
||||
"VerifySignTmpl": "验证码短信模板",
|
||||
"Enable": "启用",
|
||||
"AuthLimit": "登录限制",
|
||||
"SMTP": "邮件服务器",
|
||||
"Perm": "授权",
|
||||
"Setting": "设置",
|
||||
"Config": "配置",
|
||||
"AuthMethod": "认证方式",
|
||||
"SSO": "单点认证",
|
||||
"AppAuth": "App认证",
|
||||
"OtherAuth": "其它认证",
|
||||
"Ops": "任务",
|
||||
"OTP": "OTP(虚拟MFA)",
|
||||
"JMSSSO": "SSO Token 登录",
|
||||
"MessageSub": "消息订阅",
|
||||
"Cleaning": "定期清理",
|
||||
"Other": "其它设置",
|
||||
"CASSetting": "CAS 配置",
|
||||
"Auth": "认证设置",
|
||||
"SyncSetting": "同步设置",
|
||||
"Advanced": "高级设置",
|
||||
"InsecureCommandNotifyToSubscription": "危险命令通知已升级到消息订阅中,支持更多通知方式",
|
||||
"ApiKeyList": "API Key 列表",
|
||||
"AssetCount": "资产数量",
|
||||
@@ -810,16 +743,15 @@
|
||||
"Create": "创建",
|
||||
"Edition": "版本",
|
||||
"Email": "邮件设置",
|
||||
"EmailContent": "邮件内容定制",
|
||||
"EmailContent": "邮件内容设置",
|
||||
"Expired": "过期时间",
|
||||
"Hostname": "主机名",
|
||||
"ImportLicense": "导入许可证",
|
||||
"ImportLicenseTip": "请导入许可证",
|
||||
"Ldap": "LDAP",
|
||||
"Ldap": "LDAP设置",
|
||||
"License": "许可证",
|
||||
"Senior": "高级",
|
||||
"LicenseFile": "许可证文件",
|
||||
"PasswordCheckRule": "密码复杂度校验",
|
||||
"PasswordCheckRule": "密码校验规则",
|
||||
"Security": "安全设置",
|
||||
"SecuritySetting": "安全设置",
|
||||
"SystemMessageSubscription": "系统消息订阅",
|
||||
@@ -833,15 +765,13 @@
|
||||
"authLdapSearchFilter": "用户过滤器",
|
||||
"authLdapSearchOu": "用户OU",
|
||||
"authLdapServerUri": "LDAP地址",
|
||||
"authLdapUserAttrMap": "用户属性映射",
|
||||
"authCASAttrMap": "用户属性映射",
|
||||
"SignaturesAndTemplates": "Signatures and Templates",
|
||||
"authLdapUserAttrMap": "LDAP属性映射",
|
||||
"unselectedUser": "没有选择用户",
|
||||
"auto": "自动",
|
||||
"basicSetting": "基本设置",
|
||||
"communityEdition": "社区版",
|
||||
"consult": "咨询",
|
||||
"CreateUserSetting": "创建用户内容",
|
||||
"createUserSetting": "创建用户设置",
|
||||
"emailCustomUserCreatedBody": "创建用户邮件的内容",
|
||||
"emailCustomUserCreatedHonorific": "创建用户邮件的敬语",
|
||||
"emailCustomUserCreatedSignature": "署名",
|
||||
@@ -904,7 +834,7 @@
|
||||
"import": "导入",
|
||||
"importLdapUserTip": "请先提交LDAP配置再进行导入",
|
||||
"importLdapUserTitle": "LDAP 用户列表",
|
||||
"ldapBulkImport": "用户导入",
|
||||
"ldapBulkImport": "一键导入",
|
||||
"ldapConnectTest": "测试连接",
|
||||
"ldapLoginTest": "测试登录",
|
||||
"password": "密码",
|
||||
@@ -944,23 +874,9 @@
|
||||
"DingTalk": "钉钉",
|
||||
"dingTalkTest": "测试",
|
||||
"weComTest": "测试",
|
||||
"FeiShu": "飞书",
|
||||
"SMS": "短信设置",
|
||||
"feiShuTest": "测试",
|
||||
"setting": "设置",
|
||||
"SMSProvider": "短信服务商"
|
||||
"setting": "设置"
|
||||
},
|
||||
"tickets": {
|
||||
"OneAssigneeType": "一级受理人类型",
|
||||
"OneAssignee": "一级受理人",
|
||||
"TwoAssigneeType": "二级受理人类型",
|
||||
"TwoAssignee": "二级受理人",
|
||||
"SuperAdmin": "超级管理员",
|
||||
"OrgAdmin": "组织管理员",
|
||||
"SuperOrgAdmin": "超级管理员+组织管理员",
|
||||
"CustomUser": "自定义用户",
|
||||
"ApprovalLevel": "审批级别",
|
||||
"FlowDetail": "流程详情",
|
||||
"PermissionName": "授权规则名称",
|
||||
"Accept": "同意",
|
||||
"AssignedMe": "待我审批",
|
||||
@@ -978,11 +894,12 @@
|
||||
"status": "状态",
|
||||
"title": "标题",
|
||||
"action": "动作",
|
||||
"IPGroup": "IP 组",
|
||||
"type": "类型",
|
||||
"user": "用户",
|
||||
"Status": "状态",
|
||||
"Open": "待处理",
|
||||
"OrgName":"授权组织名称",
|
||||
"OrgName":"组织名称",
|
||||
"AssignedInfo":"审批信息",
|
||||
"OpenTicket": "创建工单",
|
||||
"HandleTicket": "处理工单",
|
||||
@@ -998,7 +915,6 @@
|
||||
"Approved": "已同意",
|
||||
"Rejected": "已拒绝",
|
||||
"Closed": "已完成",
|
||||
"StateClosed": "已关闭",
|
||||
"helpText": {
|
||||
"ips": "请输入逗号分割的IP地址组",
|
||||
"fuzzySearch": "支持模糊搜索",
|
||||
@@ -1025,8 +941,6 @@
|
||||
"UpdateNodeAssetHardwareInfo": "更新节点资产硬件信息"
|
||||
},
|
||||
"users": {
|
||||
"MessageSubscription": "消息订阅",
|
||||
"AuthSettings": "认证配置",
|
||||
"UserName": "姓名",
|
||||
"Account": "账户",
|
||||
"Authentication": "认证",
|
||||
@@ -1039,10 +953,6 @@
|
||||
"DatePasswordUpdated": "密码更新日期",
|
||||
"DescribeOfGuide": "欢迎使用JumpServer堡垒机系统,获取更多信息请点击",
|
||||
"Email": "邮件",
|
||||
"Phone": "手机号",
|
||||
"WeCom": "企业微信",
|
||||
"DingTalk": "钉钉",
|
||||
"FeiShu": "飞书",
|
||||
"FingerPrint": "指纹",
|
||||
"FirstLogin": "首次登录",
|
||||
"OrgUser": "组织用户",
|
||||
@@ -1054,7 +964,6 @@
|
||||
"Guide": "向导",
|
||||
"setWeCom": "设置企业微信认证",
|
||||
"setDingTalk": "设置钉钉认证",
|
||||
"setFeiShu": "设置飞书认证",
|
||||
"HelpText": {
|
||||
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "启用多因子认证,使账号更加安全。<br/> 启用之后您将会在下次登录时进入多因子认证绑定流程;您也可以在(个人信息->快速修改->更改多因子设置)中直接绑定!",
|
||||
"MFAOfUserFirstLoginUserGuidePage": "为了保护您和公司的安全,请妥善保管您的账户、密码和密钥等重要敏感信息;(如:设置复杂密码,并启用多因子认证)",
|
||||
@@ -1097,7 +1006,7 @@
|
||||
"resetMFAWarningMsg": "你确定要重置用户的 MFA 吗?",
|
||||
"resetMFAdSuccessMsg": "重置MFA成功, 用户可以重新设置MFA了",
|
||||
"resetPassword": "重置密码",
|
||||
"resetPasswordSuccessMsg": "已向用户发送重置密码消息",
|
||||
"resetPasswordSuccessMsg": "发送邮件任务已提交, 用户稍后会收到重置密码邮件",
|
||||
"resetPasswordWarningMsg": "你确定要发送重置用户密码的邮件吗",
|
||||
"resetSSHKey": "重置SSH密钥",
|
||||
"resetSSHKeySuccessMsg": "发送邮件任务已提交, 用户稍后会收到重置密钥邮件",
|
||||
@@ -1147,37 +1056,22 @@
|
||||
"Sender": "发送人",
|
||||
"MarkAsRead": "标记已读",
|
||||
"NoUnreadMsg": "暂无未读消息",
|
||||
"SiteMessage": "站内信",
|
||||
"SMS": "短信"
|
||||
"SiteMessage": "站内信"
|
||||
},
|
||||
"xpack": {
|
||||
"Admin": "管理员",
|
||||
"Asset": "资产",
|
||||
"Database": "数据库",
|
||||
"AssetCount": "资产数量",
|
||||
"Auditor": "审计员",
|
||||
"ChangeAuthPlan": {
|
||||
"AddAsset": "添加资产",
|
||||
"AddNode": "添加节点",
|
||||
"AddSystemUser": "添加系统用户",
|
||||
"Asset": "资产",
|
||||
"Database": "数据库",
|
||||
"DatabaseId": "数据库Id",
|
||||
"AppAmount": "应用数量",
|
||||
"SystemUserAmount": "系统用户数量",
|
||||
"SystemUser": "系统用户",
|
||||
"SystemUserId": "系统用户Id",
|
||||
"AssetAmount": "资产数量",
|
||||
"AssetAndNode": "资产和节点",
|
||||
"ChangeAuthPlan": "改密计划",
|
||||
"AssetChangeAuthPlan": "资产改密计划",
|
||||
"AppChangeAuthPlan": "应用改密计划",
|
||||
"AssetChangeAuthPlanCreate": "创建资产改密计划",
|
||||
"AppChangeAuthPlanCreate": "创建应用改密计划",
|
||||
"AssetChangeAuthPlanUpdate": "更新资产改密计划",
|
||||
"AppChangeAuthPlanUpdate": "更新应用改密计划",
|
||||
"SymbolSet": "特殊符号集合",
|
||||
"SymbolSetHelpText": "请输入此类型数据库支持的特殊符号集合,若生成的随机密码中有此类数据库不支持的特殊字符,改密计划将会失败",
|
||||
"ChangeAuthPlanCreate": "创建改密计划",
|
||||
"ChangeAuthPlanUpdate": "更新改密计划",
|
||||
"CyclePerform": "周期执行",
|
||||
"DateJoined": "创建日期",
|
||||
"DateStart": "开始日期",
|
||||
@@ -1201,7 +1095,6 @@
|
||||
"NodeAmount": "节点数量",
|
||||
"PasswordLength": "密码长度",
|
||||
"PasswordStrategy": "密码策略",
|
||||
"SecretKeyStrategy": "密钥策略",
|
||||
"RegularlyPerform": "定期执行",
|
||||
"Result": "结果",
|
||||
"Retry": "重试",
|
||||
@@ -1212,13 +1105,8 @@
|
||||
"Username": "用户名"
|
||||
},
|
||||
"Cloud": {
|
||||
"ServerAccountKey": "服务账号密钥",
|
||||
"IPNetworkSegment": "IP网段",
|
||||
"Aliyun": "阿里云",
|
||||
"Qcloud": "腾讯云",
|
||||
"QingyunPrivatecloud": "青云私有云",
|
||||
"HuaweiPrivatecloud": "华为私有云",
|
||||
"GCP": "谷歌云",
|
||||
"AWS_China": "AWS(中国)",
|
||||
"AWS_Int": "AWS(国际)",
|
||||
"HuaweiCloud": "华为云",
|
||||
@@ -1246,7 +1134,7 @@
|
||||
"Name": "名称",
|
||||
"Account":"账户",
|
||||
"Node": "节点",
|
||||
"AdminUser":"特权用户",
|
||||
"AdminUser":"管理用户",
|
||||
"Periodic":"执行周期",
|
||||
"PeriodicPerform":"定时执行",
|
||||
"RegularlyPerform": "定期执行",
|
||||
@@ -1267,9 +1155,6 @@
|
||||
"Log": "日志",
|
||||
"DeleteReleasedAssets": "删除已释放资产"
|
||||
},
|
||||
"Template": {
|
||||
"Template": "模版管理"
|
||||
},
|
||||
"Corporation": "公司",
|
||||
"Edition": "版本",
|
||||
"Execute": "执行",
|
||||
@@ -1311,7 +1196,7 @@
|
||||
"users_amount": "用户数量",
|
||||
"groups_amount": "用户组数量",
|
||||
"assets_amount": "资产数量",
|
||||
"admin_users_amount": "特权用户数量",
|
||||
"admin_users_amount": "管理用户数量",
|
||||
"system_users_amount": "系统用户数量",
|
||||
"applications_amount": "应用数量",
|
||||
"asset_perms_amount": "资产授权数量",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"": "",
|
||||
"accounts": {
|
||||
"PleaseClickLeftAssetToViewAssetAccount": "Asset account list, please click on the assets on the left to view",
|
||||
"PleaseClickLeftAssetToViewAssetAccount": "Asset account list, please click on the assets on the left to view",
|
||||
"PleaseClickLeftApplicationToViewApplicationAccount": "Application account list, please click on the application on the left to view",
|
||||
"PleaseClickLeftAssetToViewGatheredUser": "Gathered user list, please click on the assets on the left to view"
|
||||
"PleaseClickLeftAssetToViewGatheredUser": "Gathered user list, please click on the assets on the left to view"
|
||||
},
|
||||
"acl": {
|
||||
"name": "Name",
|
||||
@@ -28,12 +28,9 @@
|
||||
},
|
||||
"applications": {
|
||||
"": "",
|
||||
"updateAccountMsg": "Please update system user account info",
|
||||
"associateApplication": "Associate application",
|
||||
"RemoteApp": "Remote app",
|
||||
"Database": "Database",
|
||||
"Cloud": "Cloud",
|
||||
"App": "Application",
|
||||
"applicationsType": {
|
||||
"chrome": "Chrome",
|
||||
"mysql_workbench": "MySQL Workbench",
|
||||
@@ -85,22 +82,16 @@
|
||||
"DBInfo": "Database Info"
|
||||
},
|
||||
"assets": {
|
||||
"AppList": "Application list",
|
||||
"AssociateSystemUsers": "Associate system users",
|
||||
"AssociateAssets": "Associate assets",
|
||||
"AssociateNodes": "Associate nodes",
|
||||
"Action": "Action",
|
||||
"ActiveSelected": "Active selected",
|
||||
"AdminUser": "Admin user",
|
||||
"ReplaceNodeAssetsAdminUser":"Replace node assets admin user with this",
|
||||
"AdminUserDetail": "Admin user detail",
|
||||
"DynamicUsername": "Dynamic username",
|
||||
"AdminUserListHelpMessage": "Admin users are asset (charged server) on the root, or have NOPASSWD: ALL sudo permissions users, JumpServer users of the system using the user to `push system user`, `get assets hardware information`, etc.\n",
|
||||
"Asset": "Asset",
|
||||
"HardwareInfo": "Hardware info",
|
||||
"Hardware": "Hardware",
|
||||
"AccountList": "Account list",
|
||||
"LoginOption": "Login option",
|
||||
"AssetDetail": "Asset detail",
|
||||
"AssetList": "Asset list",
|
||||
"AssetListHelpMessage": "The left side is the asset tree, right click to create, delete, and change the tree node, authorization asset is also organized as a node, and the right side is the asset under that node\n",
|
||||
@@ -124,7 +115,6 @@
|
||||
"CommandFilterRules": "Command filter rules",
|
||||
"Comment": "Comment",
|
||||
"Cpu": "Cpu",
|
||||
"CommonUser": "Common user",
|
||||
"CreatedBy": "Created by",
|
||||
"Database": "Database",
|
||||
"DateJoined": "Date joined",
|
||||
@@ -168,7 +158,6 @@
|
||||
"PublicIp": "Public ip",
|
||||
"Push": "Push",
|
||||
"PushSystemUserNow": "Push system user now",
|
||||
"PushAllSystemUsersToAsset": "Push all system users to asset",
|
||||
"QuickUpdate": "Quick update",
|
||||
"Reachable": "Reachable",
|
||||
"Unreachable": "Unreachable",
|
||||
@@ -184,15 +173,14 @@
|
||||
"Rules": "Rules",
|
||||
"SFTPHelpMessage": "SFTP root dir, tmp, home or custom",
|
||||
"SerialNumber": "Serial number",
|
||||
"SudoHelpMessage": "Use comma split multi command, ex: /bin/whoami, /bin/ifconfig",
|
||||
"SudoHelpMessage": "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig",
|
||||
"PasswordHelpMessage": "Password or private key password",
|
||||
"SystemUser": "System user",
|
||||
"SystemUserDetail": "System user detail",
|
||||
"SystemUserListHelpMessage": "<b>System user</b> is the account JumpServer used to log into the asset, such as using root `ssh root@host`, rather than the current user username(ssh admin@host)`;<br><b>Admin user</b> is the account that already exists on an asset, and have privileged permissions, JumpServer using this create common system user, and gather hardware Etc;</br><b>Common user</b> can pre-exist assets or created automatically by the admin user.",
|
||||
"SystemUserListHelpMessage": "System user is JumpServer jump login assets used by the users, can be understood as the user login assets, such as web, sa, the dba (` ssh web@some-host `), rather than using a user the username login server jump (` ssh xiaoming@some-host `); In simple terms, users log into JumpServer using their own username, and JumpServer uses system users to log into assets. When system users are created, if you choose auto push JumpServer to use Ansible push system users into the asset, if the asset (Switch) does not support ansible, please manually fill in the account password.\n",
|
||||
"SystemUsers": "System users",
|
||||
"Test": "Test",
|
||||
"TestAssetsConnective": "Test assets connective",
|
||||
"TestAllSystemUsersConnective": "Test all system users connective",
|
||||
"TestConnection": "Test connection",
|
||||
"Type": "Type",
|
||||
"UnselectedAssets": "No asset selected or the selected asset does not support SSH protocol connection",
|
||||
@@ -231,11 +219,6 @@
|
||||
"ReLogin": "Re-Login"
|
||||
},
|
||||
"common": {
|
||||
"Logging": "Logging",
|
||||
"Database": "Database",
|
||||
"Params": "Params",
|
||||
"MFAVerify": "Verify MFA",
|
||||
"ViewSecret": "View secret",
|
||||
"ConnectWebSocketError": "Connect Websocket failed",
|
||||
"Nothing": "Nothing",
|
||||
"Action": "Action",
|
||||
@@ -251,9 +234,6 @@
|
||||
"Add": "Add",
|
||||
"PleaseAgreeToTheTerms": "Please agree to the terms",
|
||||
"PushSelected":"Push selected",
|
||||
"PushSelectedSystemUsersToAsset": "Push selected system users to asset",
|
||||
"TestSelected": "Test selected",
|
||||
"TestSelectedSystemUsersConnective": "Test selected system users connective",
|
||||
"UpdateAssetDetail": "Update more detail",
|
||||
"AddSuccessMsg": "Add success",
|
||||
"Auth": "Authorization",
|
||||
@@ -270,7 +250,7 @@
|
||||
"Confirm": "Confirm",
|
||||
"Create": "Create",
|
||||
"CreatedBy": "Created by",
|
||||
"CrontabHelpTips": "eg: Every Sunday 03:05 run <5 3 * * 0> <br>Tips:Using 5 digits linux crontab expressions<min hour day month week> (<a href='https://tool.lu/crontab/' target='_blank'>Online tools</a>) <br>Note:If both Regularly perform and Cycle perform are set, give priority to Regularly perform",
|
||||
"CrontabHelpTips": "eg: Every Sunday 03:05 run <5 3 * * 0> <br>Tips:Using 5 digits linux crontab expressions<min hour day month week> (<a href='https://tool.lu/crontab/' target='_blank'>Online tools</a>) <br>Note:If both Regularly perform and Cycle perform are set,give priority to Regularly perform",
|
||||
"DateEnd": "End date",
|
||||
"Resource": "Resource",
|
||||
"DateLast24Hours": "Last 24 hours",
|
||||
@@ -312,7 +292,7 @@
|
||||
"RemoveSuccessMsg": "Remove success",
|
||||
"Reset": "Reset",
|
||||
"Search": "Search",
|
||||
"MFAErrorMsg": "MFA Error, please check",
|
||||
"MFAErrorMsg": "MFA Error,please check",
|
||||
"InputEmailAddress": "Please enter your email address",
|
||||
"Select": "Select",
|
||||
"SelectFile": "Select file",
|
||||
@@ -527,7 +507,6 @@
|
||||
"downloadFile": "Download file",
|
||||
"hostName": "Hostname",
|
||||
"isValid": "Validity",
|
||||
"fromTicket": "From ticket",
|
||||
"isEffective": "Effective",
|
||||
"nodeCount": "Node count",
|
||||
"refreshFail": "Refresh fail",
|
||||
@@ -551,7 +530,6 @@
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"SessionDetail": "SessionDetail",
|
||||
"Accounts": "Accounts",
|
||||
"AssetAccount": "Asset account",
|
||||
"ApplicationAccount": "Application account",
|
||||
@@ -649,8 +627,7 @@
|
||||
"ApplicationPermissionUpdate": "Application permission update",
|
||||
"RemoteAppUpdate": "Remote app update",
|
||||
"ReplayStorageUpdate": "Replay storage update",
|
||||
"Detail": "Detail",
|
||||
"Activity": "Activity",
|
||||
"SessionDetail": "Sessions detail",
|
||||
"SessionOffline": "Sessions offline",
|
||||
"SessionOnline": "Sessions online",
|
||||
"Sessions": "Sessions",
|
||||
@@ -684,10 +661,6 @@
|
||||
"SiteMessageList": "Site message"
|
||||
},
|
||||
"sessions": {
|
||||
"SetToDefaultStorage": "Set to default storage",
|
||||
"SetToDefault": "Set to default",
|
||||
"SetSuccess": "Set success",
|
||||
"SetFailed": "Set failed",
|
||||
"StorageConfiguration": "Storage configuration",
|
||||
"accountKey": "Account key",
|
||||
"accountName": "Account name",
|
||||
@@ -697,7 +670,6 @@
|
||||
"target": "Target",
|
||||
"bucket": "Bucket",
|
||||
"command": "Command",
|
||||
"Activity": "Activity",
|
||||
"commandStorage": "Command storage",
|
||||
"comment": "Comment",
|
||||
"containerName": "Container name",
|
||||
@@ -753,7 +725,7 @@
|
||||
"sessionMonitor": "Session Monitor",
|
||||
"TerminateTaskSendSuccessMsg": "Terminate task has been send, Please check later",
|
||||
"helpText": {
|
||||
"esUrl": "Tip: If you have multiple hosts, use comma (, ) to split (eg: http://www.jumpserver.a.com, http://www.jumpserver.b.com)",
|
||||
"esUrl": "Tip: If you have multiple hosts, use comma (,) to split (eg: http://www.jumpserver.a.com,http://www.jumpserver.b.com)",
|
||||
"esIndex":"Es provides the default index: jumpserver",
|
||||
"esDocType": "Es provides the default document type: command",
|
||||
"s3Endpoint": "S3: http://s3.{REGION_NAME}.amazonaws.com<br>S3(China): http://s3.{REGION_NAME}.amazonaws.com.cn<br>Example: http://s3.cn-north-1.amazonaws.com.cn",
|
||||
@@ -761,28 +733,6 @@
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"SMSProvider": "SMS provider",
|
||||
"SMS": "SMS setting",
|
||||
"AlibabaCloud": "Alibaba cloud",
|
||||
"TencentCloud": "Tencent cloud",
|
||||
"VerifySignTmpl": "Verification code template",
|
||||
"Radius": "Radius",
|
||||
"Enable": "Enable",
|
||||
"Perm": "Permission",
|
||||
"SMTP": "SMTP server",
|
||||
"Setting": "Setting",
|
||||
"AuthMethod": "Auth methods",
|
||||
"AuthLimit": "Auth limit",
|
||||
"Ops": "Task",
|
||||
"OTP": "OTP(MFA)",
|
||||
"MessageSub": "Message subscription",
|
||||
"Cleaning": "Period clean",
|
||||
"Perms": "授权",
|
||||
"CASSetting": "CAS setting",
|
||||
"Other": "More...",
|
||||
"Auth": "Auth",
|
||||
"SyncSetting": "Sync setting",
|
||||
"Advanced": "Advanced",
|
||||
"InsecureCommandNotifyToSubscription": "Insecure command notification setting, change to system message subscription, support more notify method",
|
||||
"ApiKeyList": "Api key list",
|
||||
"AssetCount": "Asset count",
|
||||
@@ -814,13 +764,12 @@
|
||||
"authLdapSearchOu": "User OU",
|
||||
"authLdapServerUri": "LDAP server",
|
||||
"authLdapUserAttrMap": "User attr map",
|
||||
"authCASAttrMap": "User attr map",
|
||||
"unselectedUser": "Unselected user",
|
||||
"auto": "Auto",
|
||||
"basicSetting": "Basic setting",
|
||||
"communityEdition": "Community edition",
|
||||
"consult": "Consult",
|
||||
"CreateUserSetting": "Create User setting",
|
||||
"createUserSetting": "Create User setting",
|
||||
"emailCustomUserCreatedBody": "Create user email content",
|
||||
"emailCustomUserCreatedHonorific": "Create user honorific",
|
||||
"emailCustomUserCreatedSignature": "Signature",
|
||||
@@ -843,7 +792,7 @@
|
||||
"ApiKeyList": "The API key is used to sign the request header. The header of each request is different. Please refer to the usage documentation",
|
||||
"authLdapSearchFilter": "Choice may be (cn|uid|sAMAccountName)=%(user)s)",
|
||||
"authLdapSearchOu": "Use | split User OUs",
|
||||
"authLdapUserAttrMap": "User attr map present how to map LDAP user attr to jumpserver, username, name, email is jumpserver attr",
|
||||
"authLdapUserAttrMap": "User attr map present how to map LDAP user attr to jumpserver, username,name,email is jumpserver attr",
|
||||
"emailCustomUserCreatedBody": "Tips:When creating a user, send the content of the email",
|
||||
"emailCustomUserCreatedHonorific": "Tips: When creating a user, send the honorific of the email (eg:Hello)",
|
||||
"emailCustomUserCreatedSignature": "Tips: Email signature (eg:jumpserver)",
|
||||
@@ -920,8 +869,6 @@
|
||||
"DingTalk": "DingTalk",
|
||||
"dingTalkTest": "Test",
|
||||
"weComTest": "Test",
|
||||
"FeiShu": "FeiShu",
|
||||
"feiShuTest": "Test",
|
||||
"setting": "Setting"
|
||||
},
|
||||
|
||||
@@ -990,8 +937,6 @@
|
||||
"UpdateNodeAssetHardwareInfo": "Update node asset hardware information"
|
||||
},
|
||||
"users": {
|
||||
"MessageSubscription": "Message Subscription",
|
||||
"AuthSettings": "Auth settings",
|
||||
"UserName": "Name",
|
||||
"Account": "Account",
|
||||
"Existing":"Existing",
|
||||
@@ -1004,14 +949,9 @@
|
||||
"DatePasswordLastUpdated": "Date password last updated",
|
||||
"setWeCom": "Set wecom login",
|
||||
"setDingTalk": "Set dingtalk login",
|
||||
"setFeiShu": "Set feishu login",
|
||||
"DatePasswordUpdated": "Date password updated",
|
||||
"DescribeOfGuide": "Welcome to JumpServer. Click here for more information",
|
||||
"Email": "Email",
|
||||
"Phone": "Phone",
|
||||
"WeCom": "WeCom",
|
||||
"DingTalk": "DingTalk",
|
||||
"FeiShu": "FeiShu",
|
||||
"FingerPrint": "Fingerprint",
|
||||
"FirstLogin": "First login",
|
||||
"InviteUser": "Invite user",
|
||||
@@ -1063,7 +1003,7 @@
|
||||
"resetMFAWarningMsg": "This will reset the user MFA setting, user can reset it",
|
||||
"resetMFAdSuccessMsg": "Reset MFA success",
|
||||
"resetPassword": "Reset password",
|
||||
"resetPasswordSuccessMsg": "A password reset message has been sent to the user",
|
||||
"resetPasswordSuccessMsg": "An e-mail has been sent to the user`s mailbox",
|
||||
"resetPasswordWarningMsg": "This will reset the user password and send a reset mail",
|
||||
"resetSSHKey": "Reset SSH key",
|
||||
"resetSSHKeySuccessMsg": "An e-mail has been sent to the user`s mailbox",
|
||||
@@ -1110,35 +1050,22 @@
|
||||
"Sender": "Sender",
|
||||
"MarkAsRead": "Mark as read",
|
||||
"NoUnreadMsg": "No unread messages",
|
||||
"SiteMessage": "Site messages",
|
||||
"SMS": "SMS"
|
||||
"SiteMessage": "Site messages"
|
||||
},
|
||||
"xpack": {
|
||||
"Admin": "Admin",
|
||||
"Asset": "Asset",
|
||||
"Database": "Database",
|
||||
"AssetCount": "Asset count",
|
||||
"Auditor": "Auditor",
|
||||
"ChangeAuthPlan": {
|
||||
"AddAsset": "Add asset",
|
||||
"AddNode": "Add node",
|
||||
"AddSystemUser": "Add systemuser",
|
||||
"Asset": "Asset",
|
||||
"Database": "Database",
|
||||
"DatabaseId": "Database Id",
|
||||
"SystemUser": "SystemUser",
|
||||
"SystemUserId": "SystemUser Id",
|
||||
"AssetAmount": "Asset",
|
||||
"AssetAndNode": "Asset and Node",
|
||||
"ChangeAuthPlan": "Change Auth Plan",
|
||||
"AssetChangeAuthPlan": "Asset Change Auth Plan",
|
||||
"AppChangeAuthPlan": "App Change Auth Plan",
|
||||
"AssetChangeAuthPlanCreate": "Create Asset change auth plan",
|
||||
"AppChangeAuthPlanCreate": "Create App change auth plan",
|
||||
"AssetChangeAuthPlanUpdate": "Update Asset change auth plan",
|
||||
"AppChangeAuthPlanUpdate": "Update App change auth plan",
|
||||
"SymbolSet": "Special symbol set",
|
||||
"SymbolSetHelpText": "Please enter the special symbol set supported by this type of database. If there are special characters in the generated random password that are not supported by this type of database, the password change plan will fail",
|
||||
"ChangeAuthPlanCreate": "Create change auth plan",
|
||||
"ChangeAuthPlanUpdate": "Update change auth plan",
|
||||
"CyclePerform": "Cycle perform",
|
||||
"DateJoined": "Date joined",
|
||||
"DateStart": "Date start",
|
||||
@@ -1172,13 +1099,8 @@
|
||||
"Username": "Username"
|
||||
},
|
||||
"Cloud": {
|
||||
"ServerAccountKey": "Server Account Key",
|
||||
"IPNetworkSegment": "Ip Network Segment",
|
||||
"Aliyun": "Ali Cloud",
|
||||
"Qcloud": "Tencent Cloud",
|
||||
"QingyunPrivatecloud": "Qingyun Private Cloud",
|
||||
"HuaweiPrivatecloud": "Huawei Private Cloud",
|
||||
"GCP": "Google Cloud Platform",
|
||||
"AWS_China": "AWS(China)",
|
||||
"AWS_Int": "AWS(International)",
|
||||
"HuaweiCloud": "Huawei Cloud",
|
||||
@@ -1259,7 +1181,7 @@
|
||||
"Organization": {
|
||||
"OrganizationCreate": "Create organization",
|
||||
"OrganizationDetail": "Org detail",
|
||||
"OrganizationList": "Organizations",
|
||||
"OrganizationList": "Organlizations",
|
||||
"OrganizationUpdate": "Update org",
|
||||
"OrganizationMembership": "Organization membership",
|
||||
"DeleteOrgTitle":"Please ensure that the following information in the organization has been deleted",
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
</template>
|
||||
<script>
|
||||
import AutoDataForm from '@/components/AutoDataForm'
|
||||
import { getUpdateObjURL } from '@/utils/common'
|
||||
export default {
|
||||
name: 'GenericCreateUpdateForm',
|
||||
components: {
|
||||
@@ -112,7 +111,7 @@ export default {
|
||||
}
|
||||
},
|
||||
// 获取提交的方法
|
||||
submitMethod: {
|
||||
getMethod: {
|
||||
type: Function,
|
||||
default: function() {
|
||||
const params = this.$route.params
|
||||
@@ -130,31 +129,36 @@ export default {
|
||||
const params = this.$route.params
|
||||
let url = this.url
|
||||
if (params.id) {
|
||||
url = getUpdateObjURL(url, params.id)
|
||||
url = `${url}${params.id}/`
|
||||
}
|
||||
return url
|
||||
}
|
||||
},
|
||||
emitPerformSuccessMsg: {
|
||||
onPerformSuccess: {
|
||||
type: Function,
|
||||
default(method, res, addContinue) {
|
||||
default(res, method, vm, addContinue) {
|
||||
let msg = method === 'post' ? this.createSuccessMsg : this.updateSuccessMsg
|
||||
if (addContinue) {
|
||||
msg = this.saveSuccessContinueMsg
|
||||
}
|
||||
let msgLinkName = ''
|
||||
let msgLinkName = this.$t('common.Resource')
|
||||
if (res.name) {
|
||||
msgLinkName = res.name
|
||||
} else if (res.hostname) {
|
||||
msgLinkName = res.hostname
|
||||
}
|
||||
const detailRoute = this.objectDetailRoute
|
||||
detailRoute['params'] = { 'id': res.id }
|
||||
const route = this.getNextRoute(res, method)
|
||||
this.$emit('submitSuccess', res)
|
||||
const h = this.$createElement
|
||||
this.$log.debug('router is: ', detailRoute)
|
||||
if (this.hasDetailInMsg) {
|
||||
this.$message({
|
||||
message: h('p', null, [
|
||||
h('el-link', {
|
||||
on: {
|
||||
click: () => this.$router.push(this.objectDetailRoute)
|
||||
click: () => this.$router.push(detailRoute)
|
||||
},
|
||||
style: { 'vertical-align': 'top' }
|
||||
}, msgLinkName),
|
||||
@@ -170,18 +174,6 @@ export default {
|
||||
} else {
|
||||
this.$message.success(msg)
|
||||
}
|
||||
}
|
||||
},
|
||||
onPerformSuccess: {
|
||||
type: Function,
|
||||
default(res, method, vm, addContinue) {
|
||||
const route = this.getNextRoute(res, method)
|
||||
if (!(route.params && route.params.id)) {
|
||||
route['params'] = { 'id': res.id }
|
||||
}
|
||||
this.$emit('submitSuccess', res)
|
||||
|
||||
this.emitPerformSuccessMsg(method, res, addContinue)
|
||||
if (!addContinue) {
|
||||
setTimeout(() => this.$router.push(route), 100)
|
||||
}
|
||||
@@ -223,10 +215,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
method() {
|
||||
return this.submitMethod(this)
|
||||
return this.getMethod(this)
|
||||
},
|
||||
iUrl() {
|
||||
// 更新或创建的url
|
||||
return this.getUrl()
|
||||
},
|
||||
iHasSaveContinue() {
|
||||
@@ -239,7 +230,7 @@ export default {
|
||||
if (this.hasReset != null) {
|
||||
return this.hasReset
|
||||
}
|
||||
return this.isUpdateMethod()
|
||||
return this.method === 'put'
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
@@ -255,9 +246,6 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isUpdateMethod() {
|
||||
return ['put', 'patch'].indexOf(this.method.toLowerCase()) > -1
|
||||
},
|
||||
handleSubmit(values, formName, addContinue) {
|
||||
let handler = this.onSubmit || this.defaultOnSubmit
|
||||
handler = handler.bind(this)
|
||||
@@ -273,11 +261,11 @@ export default {
|
||||
},
|
||||
async getFormValue() {
|
||||
const cloneFrom = this.$route.query['clone_from']
|
||||
if (!this.isUpdateMethod() && !cloneFrom) {
|
||||
if (this.method !== 'put' && !cloneFrom) {
|
||||
return Object.assign(this.form, this.initial)
|
||||
}
|
||||
let object = this.object
|
||||
if (!object || Object.keys(object).length === 0) {
|
||||
if (!object) {
|
||||
if (cloneFrom) {
|
||||
this.$log.debug('Clone from: ', cloneFrom)
|
||||
const url = `${this.url}${cloneFrom}/`
|
||||
|
||||
@@ -175,12 +175,8 @@ export default {
|
||||
},
|
||||
defaultUpdate() {
|
||||
const id = this.$route.params.id
|
||||
let route = this.validActions.updateRoute
|
||||
if (typeof route === 'string') {
|
||||
route = { name: route, params: {}}
|
||||
}
|
||||
route.params.id = id
|
||||
this.$router.push(route)
|
||||
const routeName = this.validActions.updateRoute
|
||||
this.$router.push({ name: routeName, params: { id: id }})
|
||||
},
|
||||
getObject() {
|
||||
const url = this.validActions.detailApiUrl
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ListTable ref="ListTable" v-bind="$attrs" v-on="$listeners" />
|
||||
<ListTable ref="ListTable" v-bind="iAttrs" v-on="$listeners" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -11,15 +11,16 @@ export default {
|
||||
ListTable
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currentOrgIsRoot'])
|
||||
},
|
||||
created() {
|
||||
const headerActions = this.$attrs['header-actions'] || {}
|
||||
if (headerActions.canCreate === undefined && this.currentOrgIsRoot) {
|
||||
_.set(this.$attrs, 'header-actions.canCreate', false)
|
||||
}
|
||||
if (headerActions.hasImport === undefined && this.currentOrgIsRoot) {
|
||||
_.set(this.$attrs, 'header-actions.hasImport', false)
|
||||
...mapGetters(['currentOrgIsRoot']),
|
||||
iAttrs() {
|
||||
const attrs = _.cloneDeep(this.$attrs)
|
||||
const canCreate = _.get(attrs, 'header-actions.canCreate', null)
|
||||
this.$log.debug('Can create: ', canCreate)
|
||||
if (canCreate === null && this.currentOrgIsRoot) {
|
||||
_.set(attrs, 'header-actions.canCreate', false)
|
||||
}
|
||||
this.$log.debug('List table Attrs: ', attrs)
|
||||
return attrs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<template>
|
||||
<Page v-bind="$attrs">
|
||||
<Page>
|
||||
<el-alert v-if="helpMessage" type="success"> {{ helpMessage }} </el-alert>
|
||||
<TreeTable
|
||||
ref="TreeTable"
|
||||
v-bind="$attrs"
|
||||
:table-config="tableConfig"
|
||||
:header-actions="iHeaderActions"
|
||||
:tree-setting="treeSetting"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<template #table>
|
||||
@@ -24,16 +27,23 @@ export default {
|
||||
components: {
|
||||
Page, TreeTable
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currentOrgIsRoot'])
|
||||
},
|
||||
created() {
|
||||
const headerActions = this.$attrs['header-actions'] || {}
|
||||
if (headerActions.canCreate === undefined && this.currentOrgIsRoot) {
|
||||
_.set(this.$attrs, 'header-actions.canCreate', false)
|
||||
props: {
|
||||
...TreeTable.props,
|
||||
helpMessage: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
if (headerActions.hasImport === undefined && this.currentOrgIsRoot) {
|
||||
_.set(this.$attrs, 'header-actions.hasImport', false)
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currentOrg']),
|
||||
iHeaderActions() {
|
||||
const attrs = _.cloneDeep(this.headerActions)
|
||||
const canCreate = _.get(attrs, 'canCreate', null)
|
||||
// this.$log.debug('Current org: ', this.currentOrg)
|
||||
if (canCreate === null && this.currentOrg && this.currentOrg.is_root) {
|
||||
_.set(attrs, 'canCreate', false)
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<Dialog
|
||||
:title="this.$t('common.updateSelected')"
|
||||
:visible.sync="iVisible"
|
||||
:visible.sync="dialogSetting.dialogVisible"
|
||||
width="70%"
|
||||
top="1vh"
|
||||
:show-cancel="false"
|
||||
@@ -45,13 +45,13 @@ export default {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
formSetting: {
|
||||
dialogSetting: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
formSetting: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
@@ -62,16 +62,6 @@ export default {
|
||||
iFormSetting: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iVisible: {
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
},
|
||||
get() {
|
||||
return this.visible
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const defaultFormSetting = this.getDefaultFormSetting()
|
||||
this.iFormSetting = Object.assign({}, this.formSetting, defaultFormSetting)
|
||||
@@ -90,7 +80,7 @@ export default {
|
||||
getDefaultFormSetting() {
|
||||
const vm = this
|
||||
return {
|
||||
submitMethod: () => 'post',
|
||||
getMethod: () => 'post',
|
||||
cleanFormValue: function(value) {
|
||||
const filterValue = {}
|
||||
Object.keys(value).filter((key) => vm.checkedFields.includes(key)).forEach((key) => {
|
||||
@@ -110,7 +100,7 @@ export default {
|
||||
this.$axios.patch(url, validValues).then((res) => {
|
||||
vm.$emit('update')
|
||||
this.$message.success(msg)
|
||||
this.iVisible = false
|
||||
vm.dialogSetting.dialogVisible = false
|
||||
}).catch(error => {
|
||||
this.$emit('submitError', error)
|
||||
const response = error.response
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<el-option
|
||||
v-for="item in userAdminOrgList"
|
||||
:key="item.id"
|
||||
:selected="item.id === currentOrg.id"
|
||||
selected="item.id == currentOrg.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
@@ -48,8 +48,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
needShow() {
|
||||
const hasValidLicense = this.$store.getters.hasValidLicense
|
||||
return !this.isCollapse && this.inAdminPage && hasValidLicense
|
||||
const otherOrgs = this.userAdminOrgList.filter(org => {
|
||||
return !org.is_root && !org.is_default
|
||||
})
|
||||
return !this.isCollapse && otherOrgs.length > 0 && this.inAdminPage
|
||||
},
|
||||
changeOrg(orgId) {
|
||||
orgUtil.changeOrg(orgId)
|
||||
|
||||
@@ -82,6 +82,7 @@ export default {
|
||||
case 'userPage':
|
||||
if (this.currentOrgUsePagePerm) {
|
||||
this.$store.dispatch('users/setCurrentRole', rolec.USER)
|
||||
// console.log('Switch to: ', rolec.USER)
|
||||
window.location.href = `/ui/`
|
||||
}
|
||||
break
|
||||
@@ -95,6 +96,11 @@ export default {
|
||||
}
|
||||
},
|
||||
logout() {
|
||||
// Clean Status
|
||||
const statusList = ['currentOrg', 'currentRole', 'jms_current_org', 'jms_current_role', 'sidebarStatus', 'X-JMS-ORG', 'activeTab']
|
||||
for (const i in statusList) {
|
||||
this.$cookie.delete(statusList[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
v-for="msg of messages"
|
||||
:key="msg.id"
|
||||
class="msg-item"
|
||||
:class="msg['has_read'] ? 'msg-read' : 'msg-unread'"
|
||||
:class="msg.has_read ? 'msg-read' : 'msg-unread'"
|
||||
@mouseover="hoverMsgId = msg.id"
|
||||
@mouseleave="hoverMsgId = ''"
|
||||
@click="showMsgDetail(msg)"
|
||||
|
||||
@@ -8,23 +8,10 @@
|
||||
</template>
|
||||
|
||||
<div>
|
||||
<el-tabs
|
||||
v-if="submenu.length > 0"
|
||||
slot="submenu"
|
||||
v-model="iActiveMenu"
|
||||
class="page-submenu"
|
||||
@tab-click="handleTabClick"
|
||||
>
|
||||
<el-tabs v-if="submenu.length > 0" slot="submenu" v-model="iActiveMenu" class="page-submenu" @tab-click="handleTabClick">
|
||||
<template v-for="item in submenu">
|
||||
<el-tab-pane
|
||||
v-if="checkShow(item)"
|
||||
:key="item.name"
|
||||
:label-content="item.labelContent"
|
||||
:name="item.name"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
<el-tab-pane :key="item.name" :label-content="item.labelContent" :name="item.name" :disabled="item.disabled">
|
||||
<span slot="label">
|
||||
<i v-if="item.icon" class="fa " :class="item.icon" />
|
||||
{{ item.title }}
|
||||
<slot name="badge" :tab="item.name" />
|
||||
</span>
|
||||
@@ -80,13 +67,6 @@ export default {
|
||||
this.iActiveMenu = this.getPropActiveTab()
|
||||
},
|
||||
methods: {
|
||||
checkShow(item) {
|
||||
let hidden = item.hidden
|
||||
if (typeof hidden === 'function') {
|
||||
hidden = hidden()
|
||||
}
|
||||
return !hidden
|
||||
},
|
||||
handleTabClick(tab) {
|
||||
this.$emit('tab-click', tab)
|
||||
this.$emit('update:activeMenu', tab.name)
|
||||
@@ -123,16 +103,15 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-submenu >>> .el-tabs__header {
|
||||
background-color: white;
|
||||
margin-left: -25px;
|
||||
padding-left: 25px;
|
||||
margin-right: -25px;
|
||||
padding-right: 25px;
|
||||
margin-top: -30px;
|
||||
}
|
||||
|
||||
.page-submenu >>> .el-tabs__nav-wrap {
|
||||
position: static;
|
||||
}
|
||||
.page-submenu >>> .el-tabs__header {
|
||||
background-color: white;
|
||||
margin-left: -25px;
|
||||
padding-left: 25px;
|
||||
margin-right: -25px;
|
||||
padding-right: 25px;
|
||||
margin-top: -30px;
|
||||
}
|
||||
.page-submenu >>> .el-tabs__nav-wrap {
|
||||
position: static;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,7 +7,6 @@ export { default as GenericDetailPage } from './GenericDetailPage'
|
||||
export { default as TabPage } from './TabPage'
|
||||
export { default as Footer } from './Footer'
|
||||
export { default as GenericListPage } from './GenericListPage'
|
||||
export { default as GenericListTable } from './GenericListTable'
|
||||
export { default as GenericCreateUpdatePage } from './GenericCreateUpdatePage'
|
||||
export { default as GenericCreateUpdateForm } from './GenericCreateUpdateForm'
|
||||
export { default as GenericUpdateFormDialog } from './GenericUpdateFormDialog'
|
||||
|
||||
@@ -5,7 +5,6 @@ export default [
|
||||
path: 'asset-accounts',
|
||||
component: empty,
|
||||
meta: { title: i18n.t('route.AssetAccount') },
|
||||
redirect: '',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
@@ -18,7 +17,6 @@ export default [
|
||||
{
|
||||
path: 'application-accounts',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('route.AssetAccount') },
|
||||
children: [
|
||||
{
|
||||
@@ -81,83 +79,40 @@ export default [
|
||||
{
|
||||
path: 'change-auth-plan',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan') },
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan/plan' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/index.vue'),
|
||||
name: 'ChangeAuthPlanIndex',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan' }
|
||||
},
|
||||
{
|
||||
path: 'plan',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanList.vue'),
|
||||
name: 'AssetChangeAuthPlanList',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AssetChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan' },
|
||||
hidden: true
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanList.vue'),
|
||||
name: 'ChangeAuthPlanList',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan/plan' }
|
||||
},
|
||||
{
|
||||
path: 'plan/create',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'AssetChangeAuthPlanCreate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AssetChangeAuthPlanCreate'), activeMenu: '/accounts/change-auth-plan', action: 'create' },
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'ChangeAuthPlanCreate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlanCreate'), activeMenu: '/accounts/change-auth-plan/plan', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan/:id/update',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'AssetChangeAuthPlanUpdate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AssetChangeAuthPlanUpdate'), activeMenu: '/accounts/change-auth-plan', action: 'update' },
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'ChangeAuthPlanUpdate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlanUpdate'), activeMenu: '/accounts/change-auth-plan/plan', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan/:id',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanDetail/index.vue'),
|
||||
name: 'AssetChangeAuthPlanDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AssetChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan' },
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanDetail/index.vue'),
|
||||
name: 'ChangeAuthPlanDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan/plan' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan-execution/:id',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/index.vue'),
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/index.vue'),
|
||||
name: 'ChangeAuthPlanExecutionDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ExecutionDetail'), activeMenu: '/accounts/change-auth-plan' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'app-plan',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanList.vue'),
|
||||
name: 'AppChangeAuthPlanList',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AppChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'app-plan/create',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'AppChangeAuthPlanCreate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AppChangeAuthPlanCreate'), activeMenu: '/accounts/change-auth-plan', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'app-plan/:id',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/ChangeAuthPlanDetail/index.vue'),
|
||||
name: 'AppChangeAuthPlanDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AppChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'app-plan/:id/update',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'AppChangeAuthPlanUpdate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.AppChangeAuthPlanUpdate'), activeMenu: '/accounts/change-auth-plan', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'app-plan-execution/:id',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/ChangeAuthPlanDetail/AppChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/index.vue'),
|
||||
name: 'AppChangeAuthPlanExecutionDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ExecutionDetail'), activeMenu: '/accounts/change-auth-plan' },
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ExecutionDetail'), activeMenu: '/accounts/change-auth-plan/plan' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -38,72 +38,57 @@ export default [
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'databases',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('route.DatabaseApp') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'DatabaseAppList',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppList'),
|
||||
meta: { title: i18n.t('route.DatabaseApp') }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'DatabaseAppCreate',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.DatabaseAppCreate'), activeMenu: '/applications/databases', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
name: 'DatabaseAppUpdate',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.DatabaseAppUpdate'), activeMenu: '/applications/databases', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
name: 'DatabaseAppDetail',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppDetail/index'),
|
||||
meta: { title: i18n.t('route.DatabaseAppDetail'), activeMenu: '/applications/databases' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
path: 'database-apps',
|
||||
name: 'DatabaseAppList',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppList'),
|
||||
meta: { title: i18n.t('route.DatabaseApp') }
|
||||
},
|
||||
{
|
||||
path: 'kubernetes',
|
||||
component: empty,
|
||||
meta: { title: i18n.t('route.KubernetesApp') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'KubernetesAppList',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppList'),
|
||||
meta: { title: i18n.t('route.KubernetesApp') }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'KubernetesAppCreate',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.KubernetesAppCreate'), activeMenu: '/applications/kubernetes', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
name: 'KubernetesAppUpdate',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.KubernetesAppUpdate'), activeMenu: '/applications/kubernetes', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
name: 'KubernetesAppDetail',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppDetail/index'),
|
||||
meta: { title: i18n.t('route.KubernetesAppDetail'), activeMenu: '/applications/kubernetes' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
path: 'database-apps/create',
|
||||
name: 'DatabaseAppCreate',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.DatabaseAppCreate'), activeMenu: '/applications/database-apps', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'database-apps/:id/update',
|
||||
name: 'DatabaseAppUpdate',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.DatabaseAppUpdate'), activeMenu: '/applications/database-apps', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'database-apps/:id',
|
||||
name: 'DatabaseAppDetail',
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppDetail/index'),
|
||||
meta: { title: i18n.t('route.DatabaseAppDetail'), activeMenu: '/applications/database-apps' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps',
|
||||
name: 'KubernetesAppList',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppList'),
|
||||
meta: { title: i18n.t('route.KubernetesApp') }
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps/create',
|
||||
name: 'KubernetesAppCreate',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.KubernetesAppCreate'), activeMenu: '/applications/kubernetes-apps', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps/:id/update',
|
||||
name: 'KubernetesAppUpdate',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.KubernetesAppUpdate'), activeMenu: '/applications/kubernetes-apps', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps/:id',
|
||||
name: 'KubernetesAppDetail',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppDetail/index'),
|
||||
meta: { title: i18n.t('route.KubernetesAppDetail'), activeMenu: '/applications/kubernetes-apps' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -101,6 +101,41 @@ export default [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'admin-users',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('route.AdminUserList') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'AdminUserList',
|
||||
component: () => import('@/views/assets/AdminUser/AdminUserList'),
|
||||
meta: { title: i18n.t('route.AdminUserList'), activeMenu: '/assets/admin-users' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: () => import('@/views/assets/AdminUser/AdminUserCreateUpdate.vue'), // Parent router-view
|
||||
name: 'AdminUserCreate',
|
||||
meta: { title: i18n.t('route.AdminUserCreate'), activeMenu: '/assets/admin-users' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
component: () => import('@/views/assets/AdminUser/AdminUserCreateUpdate.vue'), // Parent router-view
|
||||
name: 'AdminUserUpdate',
|
||||
meta: { title: i18n.t('route.AdminUserUpdate'), activeMenu: '/assets/admin-users' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: () => import('@/views/assets/AdminUser/AdminUserDetail/index.vue'), // Parent router-view
|
||||
name: 'AdminUserDetail',
|
||||
meta: { title: i18n.t('route.AdminUserDetail'), activeMenu: '/assets/admin-users' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'system-users',
|
||||
component: empty,
|
||||
@@ -110,20 +145,20 @@ export default [
|
||||
{
|
||||
path: '',
|
||||
name: 'SystemUserList',
|
||||
component: () => import('@/views/assets/SystemUser/SystemUserList/index.vue'),
|
||||
component: () => import('@/views/assets/SystemUser/SystemUserList.vue'),
|
||||
meta: { title: i18n.t('route.SystemUserList'), activeMenu: '/assets/system-users' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'SystemUserCreate',
|
||||
component: () => import('@/views/assets/SystemUser/SystemUserCreateUpdate/index.vue'),
|
||||
component: () => import('@/views/assets/SystemUser/SystemUserCreateUpdate.vue'),
|
||||
meta: { title: i18n.t('route.SystemUserCreate'), activeMenu: '/assets/system-users' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
name: 'SystemUserUpdate',
|
||||
component: () => import('@/views/assets/SystemUser/SystemUserCreateUpdate/index.vue'),
|
||||
component: () => import('@/views/assets/SystemUser/SystemUserCreateUpdate.vue'),
|
||||
meta: { title: i18n.t('route.SystemUserUpdate'), activeMenu: '/assets/system-users' },
|
||||
hidden: true
|
||||
},
|
||||
|
||||
@@ -5,32 +5,24 @@ import { BASE_URL } from '@/utils/common'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: 'sessions',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('route.Sessions'), permissions: [rolec.PERM_AUDIT] },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'SessionList',
|
||||
component: () => import('@/views/sessions/SessionList/index'),
|
||||
meta: { title: i18n.t('route.Sessions'), permissions: [rolec.PERM_AUDIT] }
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
name: 'SessionDetail',
|
||||
component: () => import('@/views/sessions/SessionDetail/index'),
|
||||
meta: { title: i18n.t('route.SessionDetail'), activeMenu: '/terminal/sessions' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
path: 'session',
|
||||
name: 'SessionList',
|
||||
component: () => import('@/views/sessions/SessionList/index'),
|
||||
meta: { title: i18n.t('route.Sessions'), permissions: [rolec.PERM_AUDIT] }
|
||||
},
|
||||
{
|
||||
path: 'commands',
|
||||
path: 'command',
|
||||
name: 'CommandList',
|
||||
component: () => import('@/views/sessions/CommandList'),
|
||||
meta: { title: i18n.t('route.Commands'), permissions: [rolec.PERM_AUDIT] }
|
||||
},
|
||||
{
|
||||
path: 'sessions/:id',
|
||||
name: 'SessionDetail',
|
||||
component: () => import('@/views/sessions/SessionDetail/index'),
|
||||
meta: { title: i18n.t('route.SessionDetail'), activeMenu: '/terminal/session', permissions: [rolec.PERM_AUDIT] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/luna/?_=${Date.now()}`,
|
||||
name: 'WebTerminal',
|
||||
@@ -74,41 +66,37 @@ export default [
|
||||
},
|
||||
{
|
||||
path: 'storages',
|
||||
component: empty,
|
||||
name: 'Storage',
|
||||
component: () => import('@/views/sessions/Storage/index'),
|
||||
meta: { activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
|
||||
redirect: '',
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'Storage',
|
||||
component: () => import('@/views/sessions/Storage/index'),
|
||||
meta: { activeMenu: '/terminal/terminal' }
|
||||
},
|
||||
{
|
||||
path: 'replay-storage/create',
|
||||
name: 'CreateReplayStorage',
|
||||
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal' }
|
||||
},
|
||||
{
|
||||
path: 'replay-storage/:id/update',
|
||||
name: 'ReplayStorageUpdate',
|
||||
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal' }
|
||||
},
|
||||
{
|
||||
path: 'command-storage/create',
|
||||
name: 'CreateCommandStorage',
|
||||
component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal' }
|
||||
},
|
||||
{
|
||||
path: 'command-storage/:id/update',
|
||||
name: 'CommandStorageUpdate',
|
||||
component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal' }
|
||||
}
|
||||
]
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'replay-storage/create',
|
||||
name: 'CreateReplayStorage',
|
||||
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'command-storage/create',
|
||||
name: 'CreateCommandStorage',
|
||||
component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'replay-storage/:id/update',
|
||||
name: 'ReplayStorageUpdate',
|
||||
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'command-storage/:id/update',
|
||||
name: 'CommandStorageUpdate',
|
||||
component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
|
||||
meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import empty from '@/layout/empty'
|
||||
export default [
|
||||
{
|
||||
path: 'tickets',
|
||||
@@ -56,36 +55,5 @@ export default [
|
||||
component: () => import('@/views/tickets/CommandConfirm/Detail/index'),
|
||||
meta: { title: i18n.t('route.CommandConfirm'), activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'flows',
|
||||
name: 'TicketFlowList',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('route.TicketFlow'), icon: 'check-square-o', activeMenu: '/tickets/tickets' },
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
name: 'TicketFlowCreate',
|
||||
component: () => import('@/views/tickets/TicketFlow/FlowCreateUpdate'),
|
||||
meta: { title: i18n.t('route.TicketFlowCreate') },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
name: 'TicketFlowUpdate',
|
||||
component: () => import('@/views/tickets/TicketFlow/FlowCreateUpdate'),
|
||||
meta: { title: i18n.t('route.TicketFlowUpdate') },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'tickets/flow/:id',
|
||||
name: 'FlowDetail',
|
||||
component: () => import('@/views/tickets/TicketFlow/Detail/index'),
|
||||
meta: { title: i18n.t('route.TicketFlow'), activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -3,9 +3,9 @@ const getters = {
|
||||
device: state => state.app.device,
|
||||
token: state => state.users.token,
|
||||
currentOrg: state => state.users.currentOrg,
|
||||
currentOrgIsDefault: state => state.users.currentOrg['is_default'],
|
||||
currentOrgIsDefault: state => state.users.currentOrg.is_default,
|
||||
currentOrgIsRoot: state => {
|
||||
return state.users.currentOrg && state.users.currentOrg['is_root']
|
||||
return state.users.currentOrg && state.users.currentOrg.is_root
|
||||
},
|
||||
currentRole: state => state.users.currentRole,
|
||||
currentUser: state => state.users.profile,
|
||||
@@ -16,15 +16,16 @@ const getters = {
|
||||
currentOrgRoles: state => state.users.roles,
|
||||
currentOrgPerms: state => state.users.perms,
|
||||
MFAVerifyAt: state => state.users.MFAVerifyAt,
|
||||
MFA_TTl: state => state.settings.publicSettings['SECURITY_MFA_VERIFY_TTL'],
|
||||
MFA_TTl: state => state.settings.publicSettings.SECURITY_MFA_VERIFY_TTL,
|
||||
tableConfig: state => state.table.tableConfig,
|
||||
currentUserIsSuperAdmin: state => state.users.isSuperAdmin,
|
||||
currentUserIsAdmin: state => state.users.isAdmin,
|
||||
currentUserIsSuperAdmin: state => {
|
||||
return state.users.sysRole === 'Admin'
|
||||
},
|
||||
hasValidLicense: state => state.settings.hasValidLicense,
|
||||
userAdminOrgList: (state, getters) => {
|
||||
let orgs = state.users.orgs
|
||||
if (!getters.hasValidLicense) {
|
||||
orgs = orgs.filter(org => !org['is_root'])
|
||||
orgs = orgs.filter(org => !org.is_root)
|
||||
}
|
||||
return orgs
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ const actions = {
|
||||
getPublicSettings({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getPublicSettings().then(response => {
|
||||
const data = response.data || {}
|
||||
const faviconURL = data['LOGO_URLS']?.favicon
|
||||
const faviconURL = response.data.LOGO_URLS.favicon
|
||||
let link = document.querySelector("link[rel*='icon']")
|
||||
if (!link) {
|
||||
link = document.createElement('link')
|
||||
@@ -44,13 +43,11 @@ const actions = {
|
||||
link.rel = 'shortcut icon'
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
}
|
||||
if (faviconURL) {
|
||||
link.href = faviconURL
|
||||
}
|
||||
link.href = faviconURL
|
||||
|
||||
// 动态修改Title
|
||||
document.title = data['LOGIN_TITLE']
|
||||
commit('SET_PUBLIC_SETTINGS', data)
|
||||
document.title = response.data.LOGIN_TITLE
|
||||
commit('SET_PUBLIC_SETTINGS', response.data)
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
function getTableConfigFromLocal() {
|
||||
const configs = localStorage.getItem('tableConfig')
|
||||
try {
|
||||
return JSON.parse(configs)
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
function getTableConfigfromCookie() {
|
||||
return localStorage.getItem('tableConfig') ? JSON.parse(localStorage.getItem('tableConfig')) : {}
|
||||
}
|
||||
|
||||
const state = {
|
||||
tableConfig: getTableConfigFromLocal()
|
||||
tableConfig: getTableConfigfromCookie()
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_TABLE_CONFIG: (state, item) => {
|
||||
const _tableConfig = getTableConfigFromLocal()
|
||||
Vue.set(_tableConfig, item.key, item.value)
|
||||
SET_TABLE_CONFIG: (state, tableConfig) => {
|
||||
const _tableConfig = localStorage.getItem('tableConfig') ? JSON.parse(localStorage.getItem('tableConfig')) : {}
|
||||
Vue.set(_tableConfig, tableConfig.key, tableConfig.value)
|
||||
localStorage.setItem('tableConfig', JSON.stringify(_tableConfig))
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { logout, getProfile } from '@/api/users'
|
||||
import {
|
||||
getCurrentOrgLocal,
|
||||
getCurrentRoleLocal,
|
||||
getTokenFromCookie,
|
||||
saveCurrentOrgLocal,
|
||||
saveCurrentRoleLocal
|
||||
getCurrentOrgFromCookie,
|
||||
saveCurrentOrgToCookie,
|
||||
getCurrentRoleFromCookie,
|
||||
saveCurrentRoleToCookie
|
||||
} from '@/utils/auth'
|
||||
import { resetRouter } from '@/router'
|
||||
import rolec from '@/utils/role'
|
||||
@@ -12,19 +12,15 @@ import rolec from '@/utils/role'
|
||||
const getDefaultState = () => {
|
||||
return {
|
||||
token: getTokenFromCookie(),
|
||||
currentOrg: '',
|
||||
currentRole: '',
|
||||
currentOrg: getCurrentOrgFromCookie(),
|
||||
currentRole: getCurrentRoleFromCookie(),
|
||||
profile: {},
|
||||
username: '',
|
||||
roles: {},
|
||||
sysRole: '',
|
||||
orgs: [],
|
||||
perms: 0b00000000,
|
||||
MFAVerifyAt: null,
|
||||
isSuperAdmin: false,
|
||||
isAdmin: false,
|
||||
hasAdminPerm: false,
|
||||
hasAuditPerm: false
|
||||
isSuperAdmin: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +35,6 @@ const mutations = {
|
||||
},
|
||||
SET_PROFILE: (state, profile) => {
|
||||
state.profile = profile
|
||||
const username = profile.username
|
||||
state.username = username
|
||||
state.currentOrg = getCurrentOrgLocal(username)
|
||||
state.currentRole = getCurrentRoleLocal(username)
|
||||
state.isAdmin = profile['is_org_admin']
|
||||
state.isSuperAdmin = profile['is_superuser']
|
||||
},
|
||||
SET_ORGS: (state, orgs) => {
|
||||
state.orgs = orgs
|
||||
@@ -63,23 +53,20 @@ const mutations = {
|
||||
},
|
||||
SET_ROLES(state, roles) {
|
||||
state.roles = roles
|
||||
// rolec.PERM_ADMIN &
|
||||
},
|
||||
SET_SYS_ROLE(state, role) {
|
||||
state.sysRole = role
|
||||
},
|
||||
SET_PERMS(state, perms) {
|
||||
state.perms = perms
|
||||
state.hasAdmin = (perms & rolec.PERM_ADMIN) === rolec.PERM_ADMIN
|
||||
state.hasAudit = (perms & rolec.PERM_AUDIT) === rolec.PERM_AUDIT
|
||||
},
|
||||
SET_CURRENT_ORG(state, org) {
|
||||
saveCurrentOrgToCookie(org)
|
||||
state.currentOrg = org
|
||||
saveCurrentOrgLocal(state.username, org)
|
||||
},
|
||||
SET_CURRENT_ROLE(state, role) {
|
||||
saveCurrentRoleToCookie(role)
|
||||
state.currentRole = role
|
||||
saveCurrentRoleLocal(state.username, role)
|
||||
},
|
||||
SET_MFA_VERIFY(state) {
|
||||
state.MFAVerifyAt = (new Date()).valueOf()
|
||||
|
||||
@@ -323,31 +323,6 @@ website: http://code.google.com/p/jquerytree/
|
||||
display: inline-block;
|
||||
color: #676a6c;
|
||||
}
|
||||
.ztree li span.button.chrome_ico_docu::before {
|
||||
content: "\f268";
|
||||
font-family: FontAwesome;
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
color: #676a6c;
|
||||
}
|
||||
.ztree li span.button.database_ico_docu::before {
|
||||
content: "\f1c0";
|
||||
font-family: FontAwesome;
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
color: #676a6c;
|
||||
}
|
||||
.ztree li span.button.cloud_ico_docu::before {
|
||||
content: "\f0c2";
|
||||
font-family: FontAwesome;
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
color: #676a6c;
|
||||
}
|
||||
|
||||
.ztree li span.button.windows_ico_docu::before {
|
||||
content: "\f17a";
|
||||
font-family: FontAwesome;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import GenericTreeListPage from '@/layout/components/GenericTreeListPage/index'
|
||||
import { SystemUserFormatter, DialogDetailFormatter } from '@/components/TableFormatters'
|
||||
import { ActionsFormatter, SystemUserFormatter, DialogDetailFormatter } from '@/components/TableFormatters'
|
||||
export default {
|
||||
components: {
|
||||
GenericTreeListPage
|
||||
@@ -24,7 +24,7 @@ export default {
|
||||
refresh: () => {},
|
||||
onSelected: function(event, treeNode) {
|
||||
if (treeNode.meta.type === 'node') {
|
||||
const currentNodeId = treeNode.meta.data.id
|
||||
const currentNodeId = treeNode.meta.node.id
|
||||
this.tableConfig.url = `/api/v1/perms/users/nodes/${currentNodeId}/assets/?cache_policy=1`
|
||||
}
|
||||
}.bind(this)
|
||||
@@ -33,9 +33,8 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/perms/users/assets/',
|
||||
hasTree: true,
|
||||
columns: ['hostname', 'ip', 'system_users', 'platform', 'comment', 'actions'],
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
columns: [
|
||||
{
|
||||
prop: 'hostname',
|
||||
label: this.$t('assets.Hostname'),
|
||||
formatter: DialogDetailFormatter,
|
||||
@@ -73,15 +72,17 @@ export default {
|
||||
},
|
||||
sortable: true
|
||||
},
|
||||
ip: {
|
||||
{
|
||||
prop: 'ip',
|
||||
label: this.$t('assets.ip'),
|
||||
sortable: 'custom',
|
||||
width: '150px'
|
||||
width: '180px'
|
||||
},
|
||||
system_users: {
|
||||
showOverflowTooltip: true,
|
||||
{
|
||||
prop: 'SystemUsers',
|
||||
align: 'center',
|
||||
label: this.$t('assets.SystemUsers'),
|
||||
width: '150px',
|
||||
width: '200px',
|
||||
formatter: SystemUserFormatter,
|
||||
formatterArgs: {
|
||||
getUrl: ({ row }) => {
|
||||
@@ -89,14 +90,23 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
platform: {
|
||||
{
|
||||
prop: 'platform',
|
||||
label: this.$t('assets.Platform'),
|
||||
width: '120px'
|
||||
},
|
||||
comment: {
|
||||
{
|
||||
prop: 'comment',
|
||||
label: this.$t('assets.Comment'),
|
||||
showOverflowTooltip: true,
|
||||
width: '100px'
|
||||
width: '180px'
|
||||
},
|
||||
actions: {
|
||||
{
|
||||
prop: 'id',
|
||||
align: 'center',
|
||||
formatter: ActionsFormatter,
|
||||
width: '100px',
|
||||
label: this.$t('common.action'),
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
loading: true,
|
||||
@@ -107,23 +117,30 @@ export default {
|
||||
name: 'connect',
|
||||
fa: 'fa-terminal',
|
||||
type: 'primary',
|
||||
can: ({ row }) => row.is_active,
|
||||
callback: ({ row }) => {
|
||||
can: function({ row, cellValue }) {
|
||||
return row.is_active
|
||||
},
|
||||
callback: function({ row, col, cellValue, reload }) {
|
||||
window.open(`/luna/?login_to=${row.id}`, '_blank')
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'favor',
|
||||
type: 'info',
|
||||
fa: ({ row }) => {
|
||||
return this.checkFavorite(row.id) ? 'fa-star' : 'fa-star-o'
|
||||
},
|
||||
callback: ({ row }) => this.toggleFavorite(row.id)
|
||||
fa: function({ row, cellValue }) {
|
||||
if (this.checkFavorite(row.id)) {
|
||||
return 'fa-star'
|
||||
}
|
||||
return 'fa-star-o'
|
||||
}.bind(this),
|
||||
callback: function({ row, col, cellValue, reload }) {
|
||||
this.addOrDeleteFavorite(row.id)
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
tableAttrs: {
|
||||
rowClassName({ row }) {
|
||||
return !row.is_active ? 'row_disabled' : ''
|
||||
@@ -143,32 +160,25 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
refreshAllFavorites() {
|
||||
const formatterArgs = this.tableConfig.columnsMeta.actions.formatterArgs
|
||||
formatterArgs.loading = true
|
||||
const actionsIndex = this.tableConfig.columns.length - 1
|
||||
this.tableConfig.columns[actionsIndex].formatterArgs.loading = true
|
||||
this.$axios.get('/api/v1/assets/favorite-assets/').then(resp => {
|
||||
this.allFavorites = resp
|
||||
formatterArgs.loading = false
|
||||
this.tableConfig.columns[actionsIndex].formatterArgs.loading = false
|
||||
})
|
||||
},
|
||||
favor(assetId) {
|
||||
const data = { asset: assetId }
|
||||
const url = '/api/v1/assets/favorite-assets/'
|
||||
this.$axios.post(url, data).then(
|
||||
() => this.allFavorites.push({ asset: assetId })
|
||||
)
|
||||
},
|
||||
disfavor(assetId) {
|
||||
const url = `/api/v1/assets/favorite-assets/?asset=${assetId}`
|
||||
this.$axios.delete(url).then(() => {
|
||||
this.allFavorites = this.allFavorites.filter(item => item['asset'] !== assetId)
|
||||
})
|
||||
},
|
||||
toggleFavorite(assetId) {
|
||||
const favorite = this.checkFavorite(assetId)
|
||||
if (favorite) {
|
||||
this.disfavor(assetId)
|
||||
addOrDeleteFavorite(assetId) {
|
||||
if (this.checkFavorite(assetId)) {
|
||||
this.$axios.delete(`/api/v1/assets/favorite-assets/?asset=${assetId}`).then(
|
||||
res => this.removeFavorite(assetId)
|
||||
)
|
||||
} else {
|
||||
this.favor(assetId)
|
||||
const data = {
|
||||
asset: assetId
|
||||
}
|
||||
this.$axios.post('/api/v1/assets/favorite-assets/', data).then(
|
||||
res => this.addFavorite(assetId)
|
||||
)
|
||||
}
|
||||
},
|
||||
checkFavorite(assetId) {
|
||||
@@ -179,6 +189,12 @@ export default {
|
||||
}
|
||||
})
|
||||
return ok
|
||||
},
|
||||
removeFavorite(assetId) {
|
||||
this.allFavorites = this.allFavorites.filter(item => item['asset'] !== assetId)
|
||||
},
|
||||
addFavorite(assetId) {
|
||||
this.allFavorites.push({ asset: assetId })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
<template>
|
||||
<IBox>
|
||||
<GenericCreateUpdateForm v-bind="$data" />
|
||||
<GenericCreateUpdateForm
|
||||
:fields="fields"
|
||||
:fields-meta="fieldsMeta"
|
||||
:initial="object"
|
||||
:url="url"
|
||||
:update-success-next-route="updateSuccessNextRoute"
|
||||
:clean-form-value="cleanFormValue"
|
||||
:get-method="getMethod"
|
||||
:on-perform-success="onPerformSuccess"
|
||||
:perform-submit="performSubmit"
|
||||
/>
|
||||
</IBox>
|
||||
</template>
|
||||
|
||||
@@ -72,24 +82,24 @@ export default {
|
||||
delete value['mfa_level']
|
||||
}
|
||||
return value
|
||||
},
|
||||
performSubmit(validValues) {
|
||||
if (!validValues.terms) {
|
||||
this.$message.error(this.$t('common.PleaseAgreeToTheTerms'))
|
||||
return Promise.reject()
|
||||
}
|
||||
return this.$axios['put'](this.url, validValues)
|
||||
},
|
||||
onPerformSuccess() {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
setTimeout(() => this.$router.push({ name: 'UserGuide' }), 100)
|
||||
},
|
||||
submitMethod() {
|
||||
return 'put'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMethod() {
|
||||
return 'put'
|
||||
},
|
||||
performSubmit(validValues) {
|
||||
if (!validValues.terms) {
|
||||
this.$message.error(this.$t('common.PleaseAgreeToTheTerms'))
|
||||
return Promise.reject()
|
||||
}
|
||||
return this.$axios['put'](this.url, validValues)
|
||||
},
|
||||
onPerformSuccess() {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
setTimeout(() => this.$router.push({ name: 'UserGuide' }), 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:fields-meta="fieldsMeta"
|
||||
:initial="object"
|
||||
:url="url"
|
||||
:submit-method="submitMethod"
|
||||
:get-method="getMethod"
|
||||
class="password-update"
|
||||
:update-success-next-route="updateSuccessNextRoute"
|
||||
/>
|
||||
@@ -59,7 +59,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitMethod() {
|
||||
getMethod() {
|
||||
return 'put'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,7 @@
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<QuickActions
|
||||
type="primary"
|
||||
:title="this.$t('users.AuthSettings')"
|
||||
:actions="authQuickActions"
|
||||
/>
|
||||
<QuickActions
|
||||
type="info"
|
||||
style="margin-top: 15px"
|
||||
:title="this.$t('users.MessageSubscription')"
|
||||
fa="fa-info-circle"
|
||||
:actions="messageSubscriptionQuickActions"
|
||||
/>
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<Dialog
|
||||
@@ -68,7 +57,7 @@ export default {
|
||||
showPasswordDialog: false,
|
||||
passwordInput: '',
|
||||
currentEdit: '',
|
||||
authQuickActions: [
|
||||
quickActions: [
|
||||
{
|
||||
title: this.$t('users.setWeCom'),
|
||||
attrs: {
|
||||
@@ -99,21 +88,6 @@ export default {
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('users.setFeiShu'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$store.state.users.profile.is_feishu_bound ? this.$t('common.unbind') : this.$t('common.bind'),
|
||||
disabled: this.$store.state.users.profile.source !== 'local'
|
||||
},
|
||||
has: this.$store.getters.publicSettings.AUTH_FEISHU,
|
||||
callbacks: {
|
||||
click: function() {
|
||||
this.currentEdit = 'feishu'
|
||||
this.showPasswordDialog = true
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('users.SetMFA'),
|
||||
attrs: {
|
||||
@@ -142,11 +116,7 @@ export default {
|
||||
has: this.object.mfa_enabled,
|
||||
callbacks: {
|
||||
click: function() {
|
||||
if (this.$store.state.users.profile.is_otp_secret_key_bound) {
|
||||
window.location.href = `/core/auth/profile/otp/update/?next=${this.$route.fullPath}`
|
||||
} else {
|
||||
window.location.href = `/core/auth/profile/otp/enable/start/?next=${this.$route.fullPath}`
|
||||
}
|
||||
window.location.href = `/core/auth/profile/otp/update/?next=${this.$route.fullPath}`
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
@@ -189,67 +159,6 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
messageSubscriptionQuickActions: [
|
||||
{
|
||||
title: this.$t('notifications.SiteMessage'),
|
||||
type: 'switcher',
|
||||
attrs: {
|
||||
disabled: true,
|
||||
name: 'site_msg',
|
||||
model: this.object.receive_backends.indexOf('site_msg') !== -1
|
||||
},
|
||||
callbacks: {
|
||||
change: this.updateUserReceiveBackends
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('setting.Email'),
|
||||
type: 'switcher',
|
||||
attrs: {
|
||||
name: 'email',
|
||||
model: this.object.receive_backends.indexOf('email') !== -1
|
||||
},
|
||||
callbacks: {
|
||||
change: this.updateUserReceiveBackends
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('setting.WeCom'),
|
||||
type: 'switcher',
|
||||
attrs: {
|
||||
name: 'wecom',
|
||||
model: this.object.receive_backends.indexOf('wecom') !== -1
|
||||
},
|
||||
has: this.$store.getters.publicSettings.AUTH_WECOM,
|
||||
callbacks: {
|
||||
change: this.updateUserReceiveBackends
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('setting.DingTalk'),
|
||||
type: 'switcher',
|
||||
attrs: {
|
||||
name: 'dingtalk',
|
||||
model: this.object.receive_backends.indexOf('dingtalk') !== -1
|
||||
},
|
||||
has: this.$store.getters.publicSettings.AUTH_DINGTALK,
|
||||
callbacks: {
|
||||
change: this.updateUserReceiveBackends
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('setting.FeiShu'),
|
||||
type: 'switcher',
|
||||
attrs: {
|
||||
name: 'feishu',
|
||||
model: this.object.receive_backends.indexOf('feishu') !== -1
|
||||
},
|
||||
has: this.$store.getters.publicSettings.AUTH_FEISHU,
|
||||
callbacks: {
|
||||
change: this.updateUserReceiveBackends
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -321,27 +230,6 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateUserReceiveBackends(val) {
|
||||
this.$axios.patch(
|
||||
`/api/v1/notifications/user-msg-subscription/${this.object.id}/`,
|
||||
{ 'receive_backends': this.getReceiveBackendList() }
|
||||
).then(res => {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
}).catch(err => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + err))
|
||||
})
|
||||
},
|
||||
getReceiveBackendList() {
|
||||
const backendList = []
|
||||
for (const backend of this.messageSubscriptionQuickActions) {
|
||||
const name = backend.attrs.name
|
||||
const enabled = backend.attrs.model
|
||||
if (enabled) {
|
||||
backendList.push(name)
|
||||
}
|
||||
}
|
||||
return backendList
|
||||
},
|
||||
passConfirm() {
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/password/verify/`, {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:fields-meta="fieldsMeta"
|
||||
:initial="object"
|
||||
:url="url"
|
||||
:submit-method="submitMethod"
|
||||
:get-method="getMethod"
|
||||
/>
|
||||
</IBox>
|
||||
</template>
|
||||
@@ -47,8 +47,8 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitMethod() {
|
||||
return 'patch'
|
||||
getMethod() {
|
||||
return 'put'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:fields-meta="fieldsMeta"
|
||||
:initial="object"
|
||||
:url="url"
|
||||
:submit-method="submitMethod"
|
||||
:get-method="getMethod"
|
||||
:more-buttons="moreButtons"
|
||||
:on-perform-success="onPerformSuccess"
|
||||
/>
|
||||
@@ -65,7 +65,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitMethod() {
|
||||
getMethod() {
|
||||
return 'put'
|
||||
},
|
||||
onPerformSuccess() {
|
||||
|
||||
@@ -8,32 +8,34 @@ export function getTokenFromCookie() {
|
||||
return VueCookie.get(TOKEN_KEY)
|
||||
}
|
||||
|
||||
export function getCurrentRoleLocal(username) {
|
||||
const key = CURRENT_ROLE_KEY + '_' + username
|
||||
const role = localStorage.getItem(key)
|
||||
export function getCurrentRoleFromCookie() {
|
||||
const role = VueCookie.get(CURRENT_ROLE_KEY)
|
||||
if (role) {
|
||||
return parseInt(role) || null
|
||||
}
|
||||
return role
|
||||
}
|
||||
|
||||
export function saveCurrentRoleLocal(username, role) {
|
||||
const key = CURRENT_ROLE_KEY + '_' + username
|
||||
return localStorage.setItem(key, role)
|
||||
export function saveCurrentRoleToCookie(role) {
|
||||
// console.log('Save current role to cookie: ', role)
|
||||
return VueCookie.set(CURRENT_ROLE_KEY, role, 14)
|
||||
}
|
||||
|
||||
export function getCurrentOrgLocal(username) {
|
||||
const key = CURRENT_ORG_KEY + '_' + username
|
||||
const value = localStorage.getItem(key)
|
||||
export function getCurrentOrgFromCookie() {
|
||||
let org = null
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
org = JSON.parse(VueCookie.get(CURRENT_ORG_KEY))
|
||||
} catch (e) {
|
||||
return null
|
||||
// console.log('Current org in cookie: ', org)
|
||||
}
|
||||
return org
|
||||
}
|
||||
|
||||
export function saveCurrentOrgLocal(username, org) {
|
||||
const key = CURRENT_ORG_KEY + '_' + username
|
||||
localStorage.setItem(key, JSON.stringify(org))
|
||||
export function saveCurrentOrgToCookie(org) {
|
||||
VueCookie.set(CURRENT_ORG_KEY, JSON.stringify(org), 14)
|
||||
VueCookie.set('X-JMS-ORG', org.id)
|
||||
}
|
||||
|
||||
export function removeCurrentOrg() {
|
||||
return VueCookie.remove(CURRENT_ORG_KEY)
|
||||
}
|
||||
|
||||
@@ -87,15 +87,6 @@ export function toSafeLocalDateStr(d) {
|
||||
return date_s
|
||||
}
|
||||
|
||||
export function forMatAction(vm, d) {
|
||||
d.forEach(function(item, index, arr) {
|
||||
if ([vm.$t('perms.clipboardCopyPaste'), vm.$t('perms.upDownload'), vm.$t('perms.all')].includes(item)) {
|
||||
arr.splice(index, 1)
|
||||
}
|
||||
})
|
||||
return d.join(', ')
|
||||
}
|
||||
|
||||
export function getApiPath(that) {
|
||||
let pagePath = that.$route.path
|
||||
const pagePathArray = pagePath.split('/')
|
||||
@@ -223,22 +214,11 @@ export function newURL(url) {
|
||||
if (url.indexOf('//') > -1) {
|
||||
obj = new URL(url)
|
||||
} else {
|
||||
obj = new URL(url, location.origin)
|
||||
obj = new URL(url, 'http://localhost')
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
export function getUpdateObjURL(url, objId) {
|
||||
const urlObj = new URL(url, location.origin)
|
||||
let pathname = urlObj.pathname
|
||||
if (!pathname.endsWith('/')) {
|
||||
pathname += '/'
|
||||
}
|
||||
pathname += `${objId}/`
|
||||
urlObj.pathname = pathname
|
||||
return urlObj.href
|
||||
}
|
||||
|
||||
export const assignIfNot = _.partialRight(_.assignInWith, customizer)
|
||||
|
||||
const scheme = document.location.protocol
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export function openTaskPage(taskId) {
|
||||
window.open(`/#/ops/celery/task/${taskId}/log/`, '', 'width=900,height=600')
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import { refreshSessionIdAge } from '@/api/users'
|
||||
import { Message, MessageBox } from 'element-ui'
|
||||
import store from '@/store'
|
||||
import axiosRetry from 'axios-retry'
|
||||
import router from '@/router'
|
||||
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
@@ -18,13 +17,13 @@ const service = axios.create({
|
||||
function beforeRequestAddToken(config) {
|
||||
const csrfToken = getTokenFromCookie()
|
||||
if (csrfToken) {
|
||||
// let each request carry token
|
||||
// ['X-Token'] is a custom headers key
|
||||
// please modify it according to the actual situation
|
||||
config.headers['X-CSRFToken'] = csrfToken
|
||||
}
|
||||
const queryOrgId = router.currentRoute.query?.oid
|
||||
const storeOrgId = store.getters.currentOrg?.id
|
||||
const orgId = queryOrgId || storeOrgId
|
||||
if (orgId) {
|
||||
config.headers['X-JMS-ORG'] = orgId
|
||||
if (store.getters.currentOrg) {
|
||||
config.headers['X-JMS-ORG'] = store.getters.currentOrg.id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ async function checkLogin({ to, from, next }) {
|
||||
try {
|
||||
return await store.dispatch('users/getProfile')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
const status = e.response.status
|
||||
if (status === 401 || status === 403) {
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -1,109 +1,401 @@
|
||||
<template>
|
||||
<GenericTreeListPage ref="TreeTablePage" :tree-setting="treeSetting">
|
||||
<template #table>
|
||||
<AppAccountListTable ref="table" :url="accountsUrl" />
|
||||
</template>
|
||||
</GenericTreeListPage>
|
||||
<Page>
|
||||
<el-row>
|
||||
<el-col :span="11">
|
||||
<GenericListTable ref="LeftTable" class="application-table" :header-actions="leftTable.headerActions" :table-config="leftTable.tableConfig" @row-click="leftTable.tableConfig.rowClick" />
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<GenericListTable v-if="!isInit" ref="RightTable" class="application-user-table" :header-actions="rightTable.headerActions" :table-config="rightTable.tableConfig" />
|
||||
<div v-else class="noDataR">
|
||||
<div class="hintWrap">
|
||||
<div>{{ $t('accounts.PleaseClickLeftApplicationToViewApplicationAccount') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<Dialog v-if="showMFADialog" width="50" :title="this.$t('common.MFAConfirm')" :visible.sync="showMFADialog" :show-confirm="false" :show-cancel="false" :destroy-on-close="true">
|
||||
<div v-if="MFAConfirmed">
|
||||
<el-form label-position="right" label-width="80px" :model="MFAInfo">
|
||||
<el-form-item :label="this.$t('assets.Applications')">
|
||||
<el-input v-model="MFAInfo.application" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.Username')">
|
||||
<el-input v-model="MFAInfo.username" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('assets.PasswordOrToken')">
|
||||
<el-input v-model="MFAInfo.password" type="password" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-row v-else :gutter="20">
|
||||
<el-col :span="4">
|
||||
<div style="line-height: 34px;text-align: center">MFA</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-input v-model="MFAInput" />
|
||||
<span class="help-tips help-block">{{ $t('common.MFARequireForSecurity') }}</span>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="MFAConfirm">{{ this.$t('common.Confirm') }}</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
<Dialog :title="$t('common.Export')" :visible.sync="showExportDialog" :destroy-on-close="true" @confirm="handleExportConfirm()" @cancel="handleExportCancel()">
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportTypeOption">
|
||||
<el-radio v-for="option of exportTypeOptions" :key="option.value" style="padding: 10px 20px;" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="this.$t('common.imExport.ExportRange')" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportOption">
|
||||
<el-radio v-for="option of exportOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericTreeListPage from '@/layout/components/GenericTreeListPage'
|
||||
import AppAccountListTable from '@/components/AppAccountListTable'
|
||||
import { setUrlParam } from '@/utils/common'
|
||||
import Page from '@/layout/components/Page'
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import { ActionsFormatter, DetailFormatter } from '@/components/TableFormatters'
|
||||
import Dialog from '@/components/Dialog'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { createSourceIdCache } from '@/api/common'
|
||||
import * as queryUtil from '@/components/DataTable/compenents/el-data-table/utils/query'
|
||||
|
||||
export default {
|
||||
name: 'AssetAccountList',
|
||||
components: {
|
||||
GenericTreeListPage, AppAccountListTable
|
||||
GenericListTable, Page, Dialog
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
isInit: true,
|
||||
clickedRow: null,
|
||||
iShowTree: true,
|
||||
accountsUrl: '/api/v1/applications/accounts/',
|
||||
treeSetting: {
|
||||
async: false,
|
||||
showMenu: false,
|
||||
showRefresh: true,
|
||||
showAssets: false,
|
||||
treeUrl: '/api/v1/applications/applications/tree/',
|
||||
callback: {
|
||||
onSelected: function(event, treeNode) {
|
||||
let url = '/api/v1/applications/accounts/'
|
||||
const nodeId = treeNode.id
|
||||
const value = treeNode.meta.data?.value
|
||||
if (treeNode.meta.type === 'category') {
|
||||
url = setUrlParam(url, 'category', value)
|
||||
url = setUrlParam(url, 'type', '')
|
||||
} else if (treeNode.meta.type === 'type') {
|
||||
url = setUrlParam(url, 'category', '')
|
||||
url = setUrlParam(url, 'type', value)
|
||||
} else if (treeNode.meta.type === 'application') {
|
||||
url = setUrlParam(url, 'category', '')
|
||||
url = setUrlParam(url, 'type', '')
|
||||
url = setUrlParam(url, 'app', nodeId)
|
||||
showMFADialog: false,
|
||||
MFAConfirmed: false,
|
||||
MFAInput: '',
|
||||
MFAInfo: {
|
||||
systemUser: '',
|
||||
application: '',
|
||||
username: '',
|
||||
password: ''
|
||||
},
|
||||
selectedRows: '',
|
||||
showExportDialog: false,
|
||||
dialogStatus: '',
|
||||
exportOption: 'all',
|
||||
exportTypeOption: 'csv',
|
||||
clickedRow: {},
|
||||
leftTable: {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/applications/',
|
||||
columns: [
|
||||
'name', 'category_display', 'type_display', 'comment', 'org_name'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name'],
|
||||
default: ['name', 'category_display', 'type_display']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
getRoute({ row, col, cellValue }) {
|
||||
return {
|
||||
'db': 'DatabaseAppDetail', 'remote_app': 'RemoteAppDetail', 'cloud': 'KubernetesAppDetail'
|
||||
}[row.category]
|
||||
}
|
||||
},
|
||||
showOverflowTooltip: true,
|
||||
sortable: false
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
if (row === vm.clickedRow) {
|
||||
return 'row-clicked'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
rowClick: function(row, column, event) {
|
||||
vm.rightTable.tableConfig.url = `/api/v1/applications/application-users/?application_id=${row.id}`
|
||||
vm.rightTable.tableConfig.extraQuery.application_id = row.id
|
||||
vm.clickedRow = row
|
||||
vm.MFAInfo.application = row.name
|
||||
vm.isInit = false
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: false,
|
||||
hasCreate: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false
|
||||
}
|
||||
},
|
||||
rightTable: {
|
||||
tableConfig: {
|
||||
url: `/api/v1/applications/application-users/?application_id=`,
|
||||
extraQuery: {
|
||||
application_id: ''
|
||||
},
|
||||
columns: [
|
||||
'name', 'username', 'username_same_with_user', 'protocol', 'login_mode', 'priority', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'username', 'actions'],
|
||||
default: ['name', 'username', 'date_created', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'SystemUserDetail'
|
||||
},
|
||||
showOverflowTooltip: true,
|
||||
sortable: false
|
||||
},
|
||||
protocol: {
|
||||
sortable: false
|
||||
},
|
||||
login_mode: {
|
||||
sortable: false
|
||||
},
|
||||
actions: {
|
||||
label: this.$t('common.Action'),
|
||||
align: 'center',
|
||||
width: 150,
|
||||
formatter: ActionsFormatter,
|
||||
formatterArgs: {
|
||||
hasUpdate: false, // can set function(row, value)
|
||||
hasDelete: false, // can set function(row, value)
|
||||
hasClone: false,
|
||||
moreActionsTitle: this.$t('common.More'),
|
||||
extraActions: [
|
||||
{
|
||||
name: 'View',
|
||||
title: this.$t('common.View'),
|
||||
type: 'primary',
|
||||
callback: function(val) {
|
||||
this.dialogStatus = 'viewAuthInfo'
|
||||
this.MFAInfo.systemUser = val.row
|
||||
if (!this.needMFAVerify) {
|
||||
this.showMFADialog = true
|
||||
this.MFAConfirmed = true
|
||||
this.$axios.get(`/api/v1/assets/system-users/${this.MFAInfo.systemUser.id}/auth-info/`).then(res => {
|
||||
this.MFAConfirmed = true
|
||||
this.MFAInfo.username = res.username
|
||||
if (res.protocol === 'k8s') {
|
||||
this.MFAInfo.password = res.token
|
||||
} else {
|
||||
this.MFAInfo.password = res.password
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.showMFADialog = true
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
return 'row-background-color'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: false,
|
||||
hasImport: false,
|
||||
handleExport({ selectedRows }) {
|
||||
vm.selectedRows = selectedRows
|
||||
vm.dialogStatus = 'export'
|
||||
if (!vm.needMFAVerify) {
|
||||
vm.showMFADialog = false
|
||||
vm.showExportDialog = true
|
||||
} else {
|
||||
vm.showMFADialog = true
|
||||
}
|
||||
setTimeout(() => {
|
||||
vm.accountsUrl = url
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'MFA_TTl',
|
||||
'MFAVerifyAt',
|
||||
'publicSettings'
|
||||
]),
|
||||
needMFAVerify() {
|
||||
if (!this.publicSettings.SECURITY_VIEW_AUTH_NEED_MFA) {
|
||||
return false
|
||||
}
|
||||
const ttl = this.publicSettings.SECURITY_MFA_VERIFY_TTL
|
||||
const now = new Date()
|
||||
return !(this.MFAVerifyAt && (now - this.MFAVerifyAt) < ttl * 1000)
|
||||
},
|
||||
exportOptions() {
|
||||
return [
|
||||
{
|
||||
label: this.$t('common.imExport.ExportAll'),
|
||||
value: 'all',
|
||||
can: true
|
||||
},
|
||||
{
|
||||
label: this.$t('common.imExport.ExportOnlySelectedItems'),
|
||||
value: 'selected',
|
||||
can: this.selectedRows.length > 0
|
||||
}
|
||||
]
|
||||
},
|
||||
exportTypeOptions() {
|
||||
return [
|
||||
{
|
||||
label: 'CSV',
|
||||
value: 'csv',
|
||||
can: true
|
||||
},
|
||||
{
|
||||
label: 'Excel',
|
||||
value: 'xlsx',
|
||||
can: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
MFAConfirm() {
|
||||
if (this.MFAInput.length !== 6) {
|
||||
return this.$message.error(this.$t('common.MFAErrorMsg'))
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/otp/verify/`, {
|
||||
code: this.MFAInput
|
||||
}
|
||||
).then(
|
||||
res => {
|
||||
this.$store.dispatch('users/setMFAVerify')
|
||||
if (this.dialogStatus === 'export') {
|
||||
this.showMFADialog = false
|
||||
this.showExportDialog = true
|
||||
} else {
|
||||
this.$axios.get(`/api/v1/assets/system-users/${this.MFAInfo.systemUser.id}/auth-info/`).then(res => {
|
||||
this.MFAConfirmed = true
|
||||
this.MFAInfo.username = res.username
|
||||
this.MFAInfo.password = res.password
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
downloadCsv(url) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
},
|
||||
async performExport(selectRows, exportOption, q) {
|
||||
const url = `/api/v1/applications/application-user-auth-infos/`
|
||||
const query = Object.assign({}, q)
|
||||
if (exportOption === 'selected') {
|
||||
const resources = []
|
||||
const data = selectRows
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
resources.push(data[index].id)
|
||||
}
|
||||
const spm = await createSourceIdCache(resources)
|
||||
query['spm'] = spm.spm
|
||||
} else if (exportOption === 'filtered') {
|
||||
// console.log(listTableRef)
|
||||
// console.log(listTableRef.dataTable)
|
||||
// delete query['limit']
|
||||
// delete query['offset']
|
||||
}
|
||||
query['format'] = this.exportTypeOption
|
||||
const queryStr =
|
||||
(url.indexOf('?') > -1 ? '&' : '?') +
|
||||
queryUtil.stringify(query, '=', '&')
|
||||
return this.downloadCsv(url + queryStr)
|
||||
},
|
||||
async performExportConfirm() {
|
||||
const listTableRef = this.$refs.RightTable.$refs.ListTable
|
||||
const query = listTableRef.dataTable.getQuery()
|
||||
delete query['limit']
|
||||
delete query['offset']
|
||||
return this.performExport(this.selectedRows, this.exportOption, query)
|
||||
},
|
||||
async handleExportConfirm() {
|
||||
await this.performExportConfirm()
|
||||
this.showExportDialog = false
|
||||
},
|
||||
handleExportCancel() {
|
||||
this.showExportDialog = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.asset-table ::v-deep .row-clicked, .asset-user-table ::v-deep .row-background-color {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.asset-table {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
.application-table ::v-deep .row-clicked, .application-user-table ::v-deep .row-background-color {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
& >>> .table-content {
|
||||
margin-left: 21px;
|
||||
}
|
||||
& ::v-deep .el-table__row{
|
||||
height: 40px;
|
||||
& > td{
|
||||
padding: 0;
|
||||
|
||||
.application-table {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
& ::v-deep .el-table__row{
|
||||
height: 40px;
|
||||
& > td{
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.mini-button{
|
||||
width: 12px;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
text-align: center;
|
||||
padding: 9px 0;
|
||||
background-color: #1ab394;
|
||||
border-color: #1ab394;
|
||||
color: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
line-height: 1.428;
|
||||
cursor:pointer;
|
||||
}
|
||||
.noDataR{
|
||||
width: 100%;
|
||||
height: 40vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
flex-direction: column;
|
||||
.hintWrap{
|
||||
color: #D4D6E6;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.export-item {
|
||||
width: 100%;
|
||||
display: block;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
}
|
||||
.asset-user-table{
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.export-form >>> .el-form-item__label {
|
||||
line-height: 2
|
||||
}
|
||||
.application-user-table{
|
||||
padding-left:20px ;
|
||||
}
|
||||
.noDataR {
|
||||
width: 100%;
|
||||
height: 40vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
flex-direction: column;
|
||||
.hintWrap {
|
||||
color: #D4D6E6;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,63 @@
|
||||
<template>
|
||||
<GenericTreeListPage ref="TreeTablePage" :tree-setting="treeSetting">
|
||||
<template #table>
|
||||
<AccountListTable ref="table" :url="accountsUrl" />
|
||||
</template>
|
||||
</GenericTreeListPage>
|
||||
<Page>
|
||||
<el-row>
|
||||
<el-col v-show="iShowTree" :span="iShowTree?4:0">
|
||||
<AutoDataZTree
|
||||
ref="AUtoDataZTree"
|
||||
:setting="treeSetting"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="iShowTree?9:11">
|
||||
<div class="mini">
|
||||
<div style="display:block" class="mini-button" @click="iShowTree=!iShowTree">
|
||||
<i v-show="iShowTree" class="fa fa-angle-left fa-x" />
|
||||
<i v-show="!iShowTree" class="fa fa-angle-right fa-x" />
|
||||
</div>
|
||||
</div>
|
||||
<GenericListTable
|
||||
ref="LeftTable"
|
||||
class="asset-table"
|
||||
:header-actions="leftTable.headerActions"
|
||||
:table-config="leftTable.tableConfig"
|
||||
@row-click="leftTable.tableConfig.rowClick"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="iShowTree?11:13">
|
||||
<AssetUserTable
|
||||
v-if="!isInit"
|
||||
ref="RightTable"
|
||||
class="asset-user-table"
|
||||
:url="rightTable.url"
|
||||
:search-exclude="rightTable.searchExclude"
|
||||
:extra-query="rightTable.extraQuery"
|
||||
:has-left-actions="rightTable.hasLeftActions"
|
||||
:table-config="rightTable.tableConfig"
|
||||
:has-clone="false"
|
||||
:has-import="false"
|
||||
/>
|
||||
<div v-else class="noDataR">
|
||||
<div class="hintWrap">
|
||||
<div>
|
||||
{{ $t('accounts.PleaseClickLeftAssetToViewAssetAccount') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericTreeListPage from '@/layout/components/GenericTreeListPage'
|
||||
import AccountListTable from '@/components/AccountListTable'
|
||||
import { setUrlParam } from '@/utils/common'
|
||||
import Page from '@/layout/components/Page'
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import AutoDataZTree from '@/components/AutoDataZTree/index'
|
||||
import { AssetUserTable } from '@/components'
|
||||
import { DetailFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
name: 'AssetAccountList',
|
||||
components: {
|
||||
GenericTreeListPage, AccountListTable
|
||||
AutoDataZTree, GenericListTable, Page, AssetUserTable
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
@@ -22,30 +65,104 @@ export default {
|
||||
isInit: true,
|
||||
clickedRow: null,
|
||||
iShowTree: true,
|
||||
accountsUrl: '/api/v1/assets/accounts/',
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showRefresh: true,
|
||||
showRefresh: false,
|
||||
showAssets: false,
|
||||
url: '/api/v1/assets/accounts/',
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=1',
|
||||
url: '',
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/',
|
||||
callback: {
|
||||
onSelected: function(event, treeNode) {
|
||||
let url = '/api/v1/assets/accounts/'
|
||||
if (treeNode.meta.type === 'node') {
|
||||
const nodeId = treeNode.meta.data.id
|
||||
url = setUrlParam(url, 'asset', '')
|
||||
url = setUrlParam(url, 'node', nodeId)
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
const assetId = treeNode.meta.data.id
|
||||
url = setUrlParam(url, 'node', '')
|
||||
url = setUrlParam(url, 'asset', assetId)
|
||||
}
|
||||
setTimeout(() => {
|
||||
vm.accountsUrl = url
|
||||
}, 100)
|
||||
vm.leftTable.tableConfig.url = `/api/v1/assets/assets/?node_id=${treeNode.meta.node.id}`
|
||||
vm.isInit = true
|
||||
}
|
||||
}
|
||||
},
|
||||
leftTable: {
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/assets/',
|
||||
columns: [
|
||||
'hostname', 'ip', 'protocols', 'platform', 'comment', 'org_name'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['hostname', 'ip'],
|
||||
default: ['hostname', 'ip', 'platform']
|
||||
},
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AssetDetail',
|
||||
routeQuery: {
|
||||
activeTab: 'Detail'
|
||||
}
|
||||
},
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
ip: {
|
||||
showOverflowTooltip: true
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
if (row === vm.clickedRow) {
|
||||
return 'row-clicked'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
rowClick: function(row, column, event) {
|
||||
vm.rightTable.url = `/api/v1/assets/asset-users/?asset_id=${row.id}`
|
||||
vm.rightTable.extraQuery.asset_id = row.id
|
||||
vm.clickedRow = row
|
||||
vm.isInit = false
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: false,
|
||||
hasCreate: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasBulkDelete: false,
|
||||
hasColumnSetting: true,
|
||||
hasRefresh: true,
|
||||
hasBulkUpdate: false
|
||||
}
|
||||
},
|
||||
rightTable: {
|
||||
url: `/api/v1/assets/asset-users/?hostname=ShowFirstAssetRelated`,
|
||||
extraQuery: {
|
||||
latest: 1
|
||||
},
|
||||
tableConfig: {
|
||||
columns: ['name', 'username', 'version', 'backend_display', 'date_created', 'org_name', 'actions'],
|
||||
columnsShow: {
|
||||
min: ['username', 'actions'],
|
||||
default: ['name', 'username', 'version', 'backend_display', 'date_created', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: null,
|
||||
showOverflowTooltip: true,
|
||||
sortable: false
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: true, // 斑马纹表格
|
||||
border: false, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
return 'row-background-color'
|
||||
}
|
||||
}
|
||||
},
|
||||
hasLeftActions: false,
|
||||
searchExclude: ['hostname', 'id', 'ip']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
<template>
|
||||
<GenericCreateUpdatePage v-bind="$data" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import getFields from '@/views/accounts/ChangeAuthPlan/fields'
|
||||
|
||||
export default {
|
||||
name: 'AppChangeAuthPlanCreateUpdate',
|
||||
components: {
|
||||
GenericCreateUpdatePage
|
||||
},
|
||||
data() {
|
||||
const fields = getFields.bind(this)()
|
||||
return {
|
||||
url: '/api/v1/xpack/change-auth-plan/app-plan/',
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name']],
|
||||
[this.$t('assets.Applications'), ['category', 'type', 'apps', 'system_users']],
|
||||
[this.$t('xpack.ChangeAuthPlan.PasswordStrategy'), ['password_strategy', 'password', 'password_rules']],
|
||||
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
initial: {
|
||||
type: this.$route.query.type,
|
||||
category: this.$route.query.category,
|
||||
password_strategy: 'custom',
|
||||
is_periodic: true,
|
||||
password_rules: {
|
||||
length: 30
|
||||
},
|
||||
interval: 24
|
||||
},
|
||||
fieldsMeta: {
|
||||
type: {
|
||||
type: 'select',
|
||||
disabled: true
|
||||
},
|
||||
category: {
|
||||
hidden: () => true
|
||||
},
|
||||
apps: {
|
||||
label: this.$t('assets.Applications'),
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
url: `/api/v1/applications/applications/?category=${this.$route.query.category}&type=${this.$route.query.type}`,
|
||||
transformOption: (item) => {
|
||||
return { label: item.name + ' (' + item.type_display + ')', value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
system_users: {
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
url: (function() {
|
||||
let url = '/api/v1/assets/system-users/'
|
||||
const queryType = this.$route.query.type
|
||||
if (this.$route.query.category === 'remote_app') {
|
||||
url += `?protocol=rdp`
|
||||
} else if (queryType) {
|
||||
url += `?protocol=${queryType}`
|
||||
}
|
||||
return url
|
||||
}.bind(this)()),
|
||||
transformOption: (item) => {
|
||||
if (this.$route.query.type === 'k8s') {
|
||||
return { label: item.name, value: item.id }
|
||||
}
|
||||
const username = item.username || '*'
|
||||
return { label: item.name + '(' + username + ')', value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
password: fields.password,
|
||||
password_rules: fields.database_password_rules,
|
||||
is_periodic: fields.is_periodic,
|
||||
password_strategy: fields.password_strategy,
|
||||
crontab: fields.crontab,
|
||||
interval: fields.interval
|
||||
},
|
||||
createSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
|
||||
updateSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
|
||||
cleanFormValue(data) {
|
||||
if (data['password_strategy'] === 'custom') {
|
||||
delete data['password_rules']
|
||||
} else {
|
||||
delete data['password']
|
||||
}
|
||||
if (data['interval'] === '') {
|
||||
delete data['interval']
|
||||
}
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,129 +0,0 @@
|
||||
<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'
|
||||
import { DATABASE } from '@/views/perms/const'
|
||||
|
||||
export default {
|
||||
name: 'AppChangeAuthPlanList',
|
||||
components: {
|
||||
GenericListTable
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/xpack/change-auth-plan/app-plan/',
|
||||
columns: [
|
||||
'name', 'password_strategy_display',
|
||||
'periodic_display', 'run_times', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: ['name', 'password_strategy_display', 'periodic_display', 'run_times', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AppChangeAuthPlanDetail'
|
||||
}
|
||||
},
|
||||
systemuser_display: {
|
||||
label: vm.$t('xpack.ChangeAuthPlan.SystemUser'),
|
||||
width: '300px',
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
password_strategy_display: {
|
||||
label: vm.$t('xpack.ChangeAuthPlan.PasswordStrategy'),
|
||||
width: '220px',
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
periodic_display: {
|
||||
label: vm.$t('xpack.ChangeAuthPlan.Timer'),
|
||||
showOverflowTooltip: true,
|
||||
width: '150px'
|
||||
},
|
||||
run_times: {
|
||||
label: vm.$t('xpack.ChangeAuthPlan.ExecutionTimes'),
|
||||
width: '87px',
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AppChangeAuthPlanDetail',
|
||||
routeQuery: {
|
||||
activeTab: 'AppChangeAuthPlanExecutionList'
|
||||
}
|
||||
}
|
||||
},
|
||||
comment: {
|
||||
width: '90px'
|
||||
},
|
||||
actions: {
|
||||
width: '164px',
|
||||
formatterArgs: {
|
||||
onClone: ({ row }) => {
|
||||
vm.$router.push({
|
||||
name: 'AppChangeAuthPlanCreate',
|
||||
query: {
|
||||
clone_from: row.id,
|
||||
category: row.category.toLowerCase(),
|
||||
type: row.type.toLowerCase()
|
||||
}
|
||||
})
|
||||
},
|
||||
onUpdate: ({ row }) => {
|
||||
vm.$router.push({
|
||||
name: 'AppChangeAuthPlanUpdate',
|
||||
params: { id: row.id },
|
||||
query: {
|
||||
category: row.category.toLowerCase(),
|
||||
type: row.type.toLowerCase()
|
||||
}
|
||||
})
|
||||
},
|
||||
extraActions: [
|
||||
{
|
||||
title: vm.$t('xpack.Execute'),
|
||||
name: 'execute',
|
||||
type: 'info',
|
||||
callback: function({ row }) {
|
||||
this.$axios.post(
|
||||
`/api/v1/xpack/change-auth-plan/app-plan-execution/`,
|
||||
{ plan: row.id }
|
||||
).then(res => {
|
||||
openTaskPage(res['task'])
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasRefresh: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasMoreActions: false,
|
||||
moreCreates: {
|
||||
callback: (option) => {
|
||||
vm.$router.push({ name: 'AppChangeAuthPlanCreate', query: {
|
||||
category: option.category.toLowerCase(),
|
||||
type: option.name.toLowerCase()
|
||||
}})
|
||||
},
|
||||
dropdown: DATABASE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,68 +0,0 @@
|
||||
<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: 'AppChangeAuthPlanExecutionInfo',
|
||||
components: {
|
||||
DetailCard
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
detailItems() {
|
||||
return [
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.Database'),
|
||||
value: this.object.apps_display.join(', ')
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.SystemUser'),
|
||||
value: this.object.system_users_display.join(', ')
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.AppAmount'),
|
||||
value: this.object.apps_amount
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.SystemUserAmount'),
|
||||
value: this.object.system_users_amount
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.PasswordStrategy'),
|
||||
value: this.object.password_strategy_display
|
||||
},
|
||||
{
|
||||
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)
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,92 +0,0 @@
|
||||
<template>
|
||||
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
|
||||
export default {
|
||||
name: 'AppChangeAuthPlanExecutionTaskList',
|
||||
components: {
|
||||
GenericListTable
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: `/api/v1/xpack/change-auth-plan/app-plan-execution-subtask/?plan_execution_id=${this.object.id}`,
|
||||
columns: [
|
||||
'app_display', 'system_user_display', 'is_success', 'reason', 'timedelta', 'date_start', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
app_display: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.Database'),
|
||||
formatter: function(row, column, cellValue, index) {
|
||||
const to = {
|
||||
name: 'DatabaseAppDetail',
|
||||
params: { id: row.app }
|
||||
}
|
||||
return <router-link to={ to } >{ row.app_display }</router-link>
|
||||
}
|
||||
},
|
||||
system_user_display: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.SystemUser')
|
||||
},
|
||||
is_success: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.Success')
|
||||
},
|
||||
timedelta: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.TimeDelta'),
|
||||
width: '90px',
|
||||
formatter: function(row) {
|
||||
return row.timedelta.toFixed(2) + 's'
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
hasUpdate: false,
|
||||
hasClone: false,
|
||||
extraActions: [
|
||||
{
|
||||
name: 'retry',
|
||||
type: 'info',
|
||||
title: this.$t('xpack.ChangeAuthPlan.Retry'),
|
||||
callback: function({ row, tableData }) {
|
||||
this.$axios.put(
|
||||
`/api/v1/xpack/change-auth-plan/app-plan-execution-subtask/${row.id}/`,
|
||||
).then(res => {
|
||||
window.open(`/#/ops/celery/task/${res.task}/log/`, '_blank', 'toolbar=yes, width=900, height=600')
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasSearch: true,
|
||||
hasRefresh: true,
|
||||
hasLeftActions: true,
|
||||
hasRightActions: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasCreate: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,55 +0,0 @@
|
||||
<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 AppChangeAuthPlanExecutionInfo from './ChangeAuthPlanExecutionInfo'
|
||||
import AppChangeAuthPlanExecutionTaskList from './ChangeAuthPlanExecutionTaskList'
|
||||
|
||||
export default {
|
||||
name: 'AppChangeAuthPlanExecutionDetail',
|
||||
components: {
|
||||
GenericDetailPage,
|
||||
AppChangeAuthPlanExecutionInfo,
|
||||
AppChangeAuthPlanExecutionTaskList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
execution: { id: '' },
|
||||
config: {
|
||||
activeMenu: 'AppChangeAuthPlanExecutionInfo',
|
||||
actions: {
|
||||
hasUpdate: false,
|
||||
hasDelete: false
|
||||
},
|
||||
submenu: [
|
||||
{
|
||||
title: this.$t('common.BasicInfo'),
|
||||
name: 'AppChangeAuthPlanExecutionInfo'
|
||||
},
|
||||
{
|
||||
title: this.$t('xpack.ChangeAuthPlan.TaskList'),
|
||||
name: 'AppChangeAuthPlanExecutionTaskList'
|
||||
}
|
||||
],
|
||||
getTitle: this.getExecutionTitle
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getExecutionTitle() {
|
||||
return `${this.$route.meta.title}: ${this.execution.id}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
|
||||
export default {
|
||||
name: 'AppChangeAuthPlanExecutionList',
|
||||
components: {
|
||||
GenericListTable
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: `/api/v1/xpack/change-auth-plan/app-plan-execution/?plan_id=${this.object.id}`,
|
||||
columns: [
|
||||
'username', 'result_summary', 'password_strategy_display', 'timedelta', 'trigger_display',
|
||||
'apps_amount', 'system_users_amount', 'date_start', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['actions'],
|
||||
default: [
|
||||
'username', 'password_strategy_display',
|
||||
'timedelta', 'trigger_display', 'date_start', 'actions', 'result_summary'
|
||||
]
|
||||
},
|
||||
columnsMeta: {
|
||||
username: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.Username')
|
||||
},
|
||||
apps_amount: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.AppAmount')
|
||||
},
|
||||
system_users_amount: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.SystemUserAmount')
|
||||
},
|
||||
systemusers: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.SystemUser')
|
||||
},
|
||||
result_summary: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.Result'),
|
||||
width: '80px',
|
||||
showOverflowTooltip: true,
|
||||
formatter: function(row) {
|
||||
const summary = <div>
|
||||
<span class='text-primary'>{row.result_summary.succeed}</span>/
|
||||
<span class='text-danger'>{row.result_summary.failed}</span>/
|
||||
<span>{row.result_summary.total}</span>
|
||||
</div>
|
||||
return summary
|
||||
}
|
||||
},
|
||||
password_strategy_display: {
|
||||
label: this.$t('xpack.ChangeAuthPlan.PasswordStrategy'),
|
||||
width: '220px',
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
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: 'AppChangeAuthPlanExecutionDetail', 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>
|
||||
@@ -1,101 +0,0 @@
|
||||
<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: 'AppChangeAuthPlanInfo',
|
||||
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/xpack/change-auth-plan/app-plan-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.SystemUser'),
|
||||
value: this.object.systemuser_display
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.PasswordStrategy'),
|
||||
value: this.object.password_strategy_display
|
||||
},
|
||||
{
|
||||
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>
|
||||
@@ -1,112 +0,0 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="14" :sm="24">
|
||||
<GenericListTable ref="listTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</el-col>
|
||||
<el-col :md="10" :sm="24">
|
||||
<RelationCard type="info" style="margin-top: 15px" v-bind="systemuserRelationConfig" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import RelationCard from '@/components/RelationCard/index'
|
||||
import { DeleteActionFormatter, DetailFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
name: 'ChangeAuthPlanDatabase',
|
||||
components: {
|
||||
GenericListTable, RelationCard
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: `/api/v1/xpack/change-auth-plan/app-plan/${this.object.id}/systemusers/`,
|
||||
columns: [
|
||||
'name', 'username', 'delete_action'
|
||||
],
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'SystemUserDetail'
|
||||
}
|
||||
},
|
||||
delete_action: {
|
||||
prop: 'id',
|
||||
label: this.$t('common.Actions'),
|
||||
align: 'center',
|
||||
width: 150,
|
||||
objects: this.object.system_users,
|
||||
formatter: DeleteActionFormatter,
|
||||
onDelete: function(col, row, cellValue, reload) {
|
||||
this.$axios.patch(
|
||||
`/api/v1/xpack/change-auth-plan/app-plan/${this.object.id}/systemusers/?action=remove`,
|
||||
{ system_users: [row.id] }
|
||||
).then(res => {
|
||||
this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
reload()
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.deleteErrorMsg') + ' ' + error)
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
border: false
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasSearch: true,
|
||||
hasRefresh: true,
|
||||
hasLeftActions: true,
|
||||
hasRightActions: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasCreate: false,
|
||||
hasMoreActions: false
|
||||
},
|
||||
systemuserRelationConfig: {
|
||||
icon: 'fa-edit',
|
||||
title: this.$t('xpack.ChangeAuthPlan.AddSystemUser'),
|
||||
objectsAjax: {
|
||||
url: `/api/v1/assets/system-users/?protocol=${this.object.type}`,
|
||||
transformOption: (item) => {
|
||||
return { label: item.name + '(' + item.username + ')', value: item.id }
|
||||
}
|
||||
},
|
||||
// hasObjectsId: this.object.systemuser,
|
||||
showHasObjects: false,
|
||||
performAdd: (items, that) => {
|
||||
const relationUrl = `/api/v1/xpack/change-auth-plan/app-plan/${this.object.id}/systemusers/?action=add`
|
||||
const systemusers = items.map(v => v.value)
|
||||
const iHasObjects = that.iHasObjects.map(v => v.value)
|
||||
const data = {
|
||||
system_users: Array.from(new Set([...iHasObjects, ...systemusers]))
|
||||
}
|
||||
return this.$axios.patch(relationUrl, data)
|
||||
},
|
||||
onAddSuccess: (objects, that) => {
|
||||
that.iHasObjects = [...that.iHasObjects, ...objects]
|
||||
that.$refs.select2.clearSelected()
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
window.location.reload()
|
||||
this.$refs.listTable.$refs.ListTable.reloadTable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,65 +0,0 @@
|
||||
<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 ChangeAuthPlanDatabase from './ChangeAuthPlanApp/index'
|
||||
import AppChangeAuthPlanInfo from './AppChangeAuthPlanInfo'
|
||||
import AppChangeAuthPlanExecutionList from './AppChangeAuthPlanExecution/ChangeAuthPlanExecutionList'
|
||||
|
||||
export default {
|
||||
name: 'AppChangeAuthPlanDetail',
|
||||
components: {
|
||||
GenericDetailPage,
|
||||
ChangeAuthPlanDatabase,
|
||||
AppChangeAuthPlanInfo,
|
||||
AppChangeAuthPlanExecutionList
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
plan: { name: '', comment: '' },
|
||||
config: {
|
||||
activeMenu: 'AppChangeAuthPlanInfo',
|
||||
submenu: [
|
||||
{
|
||||
title: this.$t('common.BasicInfo'),
|
||||
name: 'AppChangeAuthPlanInfo'
|
||||
},
|
||||
{
|
||||
title: this.$t('xpack.ChangeAuthPlan.SystemUser'),
|
||||
name: 'ChangeAuthPlanDatabase'
|
||||
},
|
||||
{
|
||||
title: this.$t('xpack.ChangeAuthPlan.ExecutionList'),
|
||||
name: 'AppChangeAuthPlanExecutionList'
|
||||
}
|
||||
],
|
||||
actions: {
|
||||
updateCallback: () => {
|
||||
const id = this.$route.params.id
|
||||
const routeName = 'AppChangeAuthPlanUpdate'
|
||||
this.$router.push({
|
||||
name: routeName,
|
||||
params: { id: id },
|
||||
query: {
|
||||
category: vm.plan.category.toLowerCase(),
|
||||
type: vm.plan.type.toLowerCase()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,72 +0,0 @@
|
||||
<template>
|
||||
<GenericCreateUpdatePage v-bind="$data" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import getFields from '@/views/accounts/ChangeAuthPlan/fields'
|
||||
|
||||
export default {
|
||||
name: 'AssetChangeAuthPlanCreateUpdate',
|
||||
components: {
|
||||
GenericCreateUpdatePage
|
||||
},
|
||||
data() {
|
||||
const fields = getFields.bind(this)()
|
||||
return {
|
||||
url: '/api/v1/xpack/change-auth-plan/plan/',
|
||||
fields: [
|
||||
[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.Timer'), ['is_periodic', 'crontab', 'interval']],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
initial: {
|
||||
password_strategy: 'custom',
|
||||
ssh_key_strategy: 'add',
|
||||
is_periodic: true,
|
||||
is_password: true,
|
||||
is_ssh_key: false,
|
||||
password_rules: {
|
||||
length: 30
|
||||
},
|
||||
interval: 24
|
||||
},
|
||||
fieldsMeta: {
|
||||
username: fields.username,
|
||||
assets: fields.assets,
|
||||
password: fields.password,
|
||||
password_rules: fields.asset_password_rules,
|
||||
private_key: fields.private_key,
|
||||
nodes: fields.nodes,
|
||||
is_periodic: fields.is_periodic,
|
||||
is_password: fields.is_password,
|
||||
is_ssh_key: fields.is_ssh_key,
|
||||
password_strategy: fields.password_strategy,
|
||||
ssh_key_strategy: fields.ssh_key_strategy,
|
||||
crontab: fields.crontab,
|
||||
interval: fields.interval
|
||||
},
|
||||
createSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
|
||||
updateSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
|
||||
cleanFormValue(data) {
|
||||
if (data['password_strategy'] === 'custom') {
|
||||
delete data['password_rules']
|
||||
} else {
|
||||
delete data['password']
|
||||
}
|
||||
if (data['interval'] === '') {
|
||||
delete data['interval']
|
||||
}
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
129
src/views/accounts/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue
Normal file
129
src/views/accounts/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<GenericCreateUpdatePage v-bind="$data" :clean-form-value="cleanFormValue" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import { AssetSelect } from '@/components'
|
||||
import { Required } from '@/components/DataForm/rules'
|
||||
|
||||
export default {
|
||||
name: 'ChangeAuthPlanCreateUpdate',
|
||||
components: {
|
||||
GenericCreateUpdatePage
|
||||
},
|
||||
data() {
|
||||
var validatorInterval = (rule, value, callback) => {
|
||||
if (parseInt(value) < 1) {
|
||||
return callback(new Error(this.$t('xpack.ChangeAuthPlan.validatorMessage.EnsureThisValueIsGreaterThanOrEqualTo1')))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
return {
|
||||
url: '/api/v1/xpack/change-auth-plan/plan/',
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name']],
|
||||
[this.$t('xpack.Asset'), ['username', 'assets', 'nodes']],
|
||||
[this.$t('xpack.ChangeAuthPlan.PasswordStrategy'), ['password_strategy', 'password', 'password_rules']],
|
||||
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
initial: {
|
||||
password_strategy: 'custom',
|
||||
is_periodic: true,
|
||||
password_rules: {
|
||||
length: 30
|
||||
},
|
||||
interval: 24
|
||||
},
|
||||
fieldsMeta: {
|
||||
username: {
|
||||
helpText: this.$t('xpack.ChangeAuthPlan.HelpText.UsernameOfCreateUpdatePage')
|
||||
},
|
||||
assets: {
|
||||
type: 'assetSelect',
|
||||
component: AssetSelect,
|
||||
rules: [
|
||||
{ required: false }
|
||||
],
|
||||
label: this.$t('xpack.Asset')
|
||||
},
|
||||
password: {
|
||||
hidden: (formValue) => {
|
||||
return formValue.password_strategy !== 'custom'
|
||||
},
|
||||
rules: [
|
||||
{ required: this.$route.meta.action === 'create', message: this.$t('common.fieldRequiredError'), trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
password_rules: {
|
||||
type: 'group',
|
||||
items: this.generatePasswordRulesItemsFields()
|
||||
},
|
||||
nodes: {
|
||||
label: this.$t('xpack.Node'),
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
url: '/api/v1/assets/nodes/',
|
||||
transformOption: (item) => {
|
||||
return { label: item.full_value, value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
is_periodic: {
|
||||
type: 'switch'
|
||||
},
|
||||
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'),
|
||||
rules: [
|
||||
{ validator: validatorInterval }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cleanFormValue(data) {
|
||||
if (data['password_strategy'] === 'custom') {
|
||||
delete data['password_rules']
|
||||
} else {
|
||||
delete data['password']
|
||||
}
|
||||
if (data['interval'] === '') {
|
||||
delete data['interval']
|
||||
}
|
||||
return data
|
||||
},
|
||||
generatePasswordRulesItemsFields() {
|
||||
const itemsFields = []
|
||||
const items = [
|
||||
{ id: 'length', prop: 'length', label: this.$t('xpack.ChangeAuthPlan.PasswordLength') }
|
||||
]
|
||||
items.forEach((item, index, array) => {
|
||||
itemsFields.push({
|
||||
id: item.id, prop: item.prop, el: {}, attrs: {}, type: 'input', label: item.label, rules: [Required],
|
||||
hidden: (formValue) => { return ['random_one', 'random_all'].indexOf(formValue.password_strategy) === -1 }
|
||||
})
|
||||
})
|
||||
return itemsFields
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -14,7 +14,7 @@
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import RelationCard from '@/components/RelationCard/index'
|
||||
import AssetRelationCard from '@/components/AssetRelationCard'
|
||||
import { DeleteActionFormatter, DetailFormatter } from '@/components/TableFormatters'
|
||||
import { DeleteActionFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
name: 'ChangeAuthPlanAsset',
|
||||
@@ -36,12 +36,6 @@ export default {
|
||||
'hostname', 'ip', 'delete_action'
|
||||
],
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AssetDetail'
|
||||
}
|
||||
},
|
||||
delete_action: {
|
||||
prop: 'id',
|
||||
label: this.$t('common.Actions'),
|
||||
@@ -93,7 +87,8 @@ export default {
|
||||
onAddSuccess: (items, that) => {
|
||||
this.$log.debug('AssetSelect value', that.assets)
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
window.location.reload()
|
||||
this.$refs.listTable.$refs.ListTable.reloadTable()
|
||||
that.$refs.assetSelect.$refs.select2.clearSelected()
|
||||
}
|
||||
},
|
||||
nodeRelationConfig: {
|
||||
@@ -108,7 +103,7 @@ export default {
|
||||
disabled: this.$store.getters.currentOrgIsRoot,
|
||||
hasObjectsId: this.object.nodes,
|
||||
performAdd: (items, that) => {
|
||||
const relationUrl = `/api/v1/xpack/change-auth-plan/plan/${this.object.id}/nodes/?action=add`
|
||||
const relationUrl = `/api/v1/xpack/change-auth-plan/plan/${this.object.id}/`
|
||||
const nodes = items.map(v => v.value)
|
||||
const iHasObjects = that.iHasObjects.map(v => v.value)
|
||||
const data = {
|
||||
@@ -120,13 +115,16 @@ export default {
|
||||
that.iHasObjects = [...that.iHasObjects, ...objects]
|
||||
that.$refs.select2.clearSelected()
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
window.location.reload()
|
||||
this.$refs.listTable.$refs.ListTable.reloadTable()
|
||||
},
|
||||
performDelete: (item) => {
|
||||
const nodes = this.object.nodes
|
||||
const deleteNode = item.value
|
||||
nodes.splice(nodes.indexOf(deleteNode), 1)
|
||||
const data = {
|
||||
nodes: [item.value]
|
||||
nodes: nodes
|
||||
}
|
||||
const relationUrl = `/api/v1/xpack/change-auth-plan/plan/${this.object.id}/nodes/?action=remove`
|
||||
const relationUrl = `/api/v1/xpack/change-auth-plan/plan/${this.object.id}/`
|
||||
return this.$axios.patch(relationUrl, data)
|
||||
},
|
||||
onDeleteSuccess: (obj, that) => {
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
url: `/api/v1/xpack/change-auth-plan/plan-execution/?plan_id=${this.object.id}`,
|
||||
columns: [
|
||||
'username', 'assets_amount', 'nodes_amount', 'result_summary', 'password_strategy_display',
|
||||
'timedelta', 'trigger_display', 'date_start', 'actions'
|
||||
'timedelta', 'date_start', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
username: {
|
||||
@@ -74,17 +74,12 @@ export default {
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.RegularlyPerform'),
|
||||
value: this.object.crontab,
|
||||
formatter: (item, val) => {
|
||||
return <span>{this.object.is_periodic ? val : ''}</span>
|
||||
}
|
||||
value: this.object.crontab
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.CyclePerform'),
|
||||
value: this.object.interval,
|
||||
formatter: (item, val) => {
|
||||
return <span>{this.object.is_periodic ? val : ''}</span>
|
||||
}
|
||||
value: this.object.interval
|
||||
|
||||
},
|
||||
{
|
||||
key: this.$t('xpack.ChangeAuthPlan.DateJoined'),
|
||||
@@ -1,16 +1,15 @@
|
||||
<template>
|
||||
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
|
||||
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericListTable } from '@/layout/components'
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import { DetailFormatter } from '@/components/TableFormatters'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
|
||||
export default {
|
||||
name: 'AssetChangeAuthPlanList',
|
||||
name: 'ChangeAuthPlanList',
|
||||
components: {
|
||||
GenericListTable
|
||||
GenericListPage
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
@@ -21,17 +20,7 @@ export default {
|
||||
'name', 'username', 'assets_amount', 'nodes_amount', 'password_strategy_display',
|
||||
'periodic_display', 'run_times', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: ['name', 'username', 'password_strategy_display', 'periodic_display', 'run_times', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AssetChangeAuthPlanDetail'
|
||||
}
|
||||
},
|
||||
username: {
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
@@ -58,9 +47,9 @@ export default {
|
||||
width: '87px',
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AssetChangeAuthPlanDetail',
|
||||
route: 'ChangeAuthPlanDetail',
|
||||
routeQuery: {
|
||||
activeTab: 'AssetChangeAuthPlanExecutionList'
|
||||
activeTab: 'ChangeAuthPlanExecutionList'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -70,12 +59,6 @@ export default {
|
||||
actions: {
|
||||
width: '164px',
|
||||
formatterArgs: {
|
||||
onClone: ({ row }) => {
|
||||
vm.$router.push({ name: 'AssetChangeAuthPlanCreate', query: { clone_from: row.id }})
|
||||
},
|
||||
onUpdate: ({ row }) => {
|
||||
vm.$router.push({ name: 'AssetChangeAuthPlanUpdate', params: { id: row.id }})
|
||||
},
|
||||
extraActions: [
|
||||
{
|
||||
title: vm.$t('xpack.Execute'),
|
||||
@@ -86,7 +69,7 @@ export default {
|
||||
`/api/v1/xpack/change-auth-plan/plan-execution/`,
|
||||
{ plan: row.id }
|
||||
).then(res => {
|
||||
openTaskPage(res['task'])
|
||||
window.open(`/#/ops/celery/task/${res.task}/log/`, '_blank', 'toolbar=yes, width=900, height=600')
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
@@ -99,12 +82,7 @@ export default {
|
||||
hasRefresh: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasMoreActions: false,
|
||||
createRoute: () => {
|
||||
return {
|
||||
name: 'AssetChangeAuthPlanCreate'
|
||||
}
|
||||
}
|
||||
hasMoreActions: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { AssetSelect } from '@/components'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
import { Required } from '@/components/DataForm/rules'
|
||||
|
||||
var validatorInterval = (rule, value, callback) => {
|
||||
if (parseInt(value) < 1) {
|
||||
return callback(new Error(i18n.t('xpack.ChangeAuthPlan.validatorMessage.EnsureThisValueIsGreaterThanOrEqualTo1')))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
function getAssetPasswordRulesItems() {
|
||||
return [
|
||||
{
|
||||
id: 'length', prop: 'length', label: i18n.t('xpack.ChangeAuthPlan.PasswordLength'),
|
||||
rules: [Required], hidden: (formValue) => {
|
||||
return ['random_one', 'random_all'].indexOf(formValue.password_strategy) === -1 || !formValue.is_password
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function getDatabasePasswordRulesItems() {
|
||||
return [
|
||||
{
|
||||
id: 'length', prop: 'length', label: i18n.t('xpack.ChangeAuthPlan.PasswordLength'),
|
||||
rules: [Required], hidden: (formValue) => {
|
||||
return ['random_one', 'random_all'].indexOf(formValue.password_strategy) === -1
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'symbol_set', prop: 'symbol_set',
|
||||
label: i18n.t('xpack.ChangeAuthPlan.SymbolSet'),
|
||||
helpText: i18n.t('xpack.ChangeAuthPlan.SymbolSetHelpText'),
|
||||
hidden: (formValue) => {
|
||||
return ['random_one', 'random_all'].indexOf(formValue.password_strategy) === -1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function generatePasswordRulesItemsFields(obType) {
|
||||
const itemsFields = []
|
||||
let items
|
||||
if (obType === 'asset') {
|
||||
items = getAssetPasswordRulesItems()
|
||||
} else if (obType === 'database') {
|
||||
items = getDatabasePasswordRulesItems()
|
||||
}
|
||||
items.forEach((item, index, array) => {
|
||||
itemsFields.push({
|
||||
id: item.id, prop: item.prop, el: {}, attrs: {}, type: 'input', label: item.label, rules: item.rules, helpText: item.helpText,
|
||||
hidden: item.hidden })
|
||||
})
|
||||
return itemsFields
|
||||
}
|
||||
|
||||
function getFields() {
|
||||
const username = {
|
||||
helpText: i18n.t('xpack.ChangeAuthPlan.HelpText.UsernameOfCreateUpdatePage')
|
||||
}
|
||||
|
||||
const assets = {
|
||||
type: 'assetSelect',
|
||||
component: AssetSelect,
|
||||
rules: [
|
||||
{ required: false }
|
||||
],
|
||||
label: i18n.t('xpack.Asset')
|
||||
}
|
||||
|
||||
const database = {
|
||||
component: Select2,
|
||||
rules: [
|
||||
{ required: true }
|
||||
],
|
||||
label: i18n.t('xpack.Database'),
|
||||
el: {
|
||||
multiple: false,
|
||||
value: [],
|
||||
ajax: {
|
||||
url: '/api/v1/applications/applications/?category=db',
|
||||
transformOption: (item) => {
|
||||
return { label: item.name + '(' + item.type_display + ')', value: item.id, protocol: item.type }
|
||||
}
|
||||
}
|
||||
},
|
||||
on: {
|
||||
changeOptions: ([event], updateform) => {
|
||||
updateform({ systemuser: [] })
|
||||
this.fieldsMeta.systemuser.el.ajax.url = `/api/v1/assets/system-users/?protocol=${event[0].protocol}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const password = {
|
||||
hidden: (formValue) => {
|
||||
return formValue.password_strategy !== 'custom' || formValue.is_password === false
|
||||
},
|
||||
rules: [
|
||||
{ required: this.$route.meta.action === 'create', message: i18n.t('common.fieldRequiredError'), trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
const asset_password_rules = {
|
||||
type: 'group',
|
||||
items: generatePasswordRulesItemsFields('asset')
|
||||
}
|
||||
|
||||
const database_password_rules = {
|
||||
type: 'group',
|
||||
items: generatePasswordRulesItemsFields('database')
|
||||
}
|
||||
|
||||
const private_key = {
|
||||
el: {
|
||||
type: 'textarea',
|
||||
placeholder: '-----BEGIN OPENSSH PRIVATE KEY-----',
|
||||
autosize: { minRows: 3 }
|
||||
},
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_ssh_key === false
|
||||
},
|
||||
rules: [
|
||||
{ required: this.$route.meta.action === 'create', message: this.$t('common.fieldRequiredError'), trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
const nodes = {
|
||||
label: i18n.t('xpack.Node'),
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
url: '/api/v1/assets/nodes/',
|
||||
transformOption: (item) => {
|
||||
return { label: item.full_value, value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const is_password = {
|
||||
type: 'switch'
|
||||
}
|
||||
|
||||
const is_ssh_key = {
|
||||
type: 'switch'
|
||||
}
|
||||
|
||||
const password_strategy = {
|
||||
label: i18n.t('xpack.ChangeAuthPlan.PasswordStrategy'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_password === false
|
||||
}
|
||||
}
|
||||
|
||||
const ssh_key_strategy = {
|
||||
label: i18n.t('xpack.ChangeAuthPlan.SecretKeyStrategy'),
|
||||
hidden: (formValue) => {
|
||||
return formValue.is_ssh_key === false
|
||||
}
|
||||
}
|
||||
|
||||
const systemuser = {
|
||||
component: Select2,
|
||||
label: i18n.t('xpack.ChangeAuthPlan.SystemUser'),
|
||||
rules: [
|
||||
{ required: true }
|
||||
],
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
url: '/api/v1/assets/system-users/',
|
||||
transformOption: (item) => {
|
||||
return { label: item.name + '(' + item.username + ')', value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const is_periodic = {
|
||||
type: 'switch'
|
||||
}
|
||||
|
||||
const 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 {
|
||||
username: username,
|
||||
assets: assets,
|
||||
database: database,
|
||||
systemuser: systemuser,
|
||||
password: password,
|
||||
password_strategy: password_strategy,
|
||||
ssh_key_strategy: ssh_key_strategy,
|
||||
private_key: private_key,
|
||||
asset_password_rules: asset_password_rules,
|
||||
database_password_rules: database_password_rules,
|
||||
nodes: nodes,
|
||||
is_password: is_password,
|
||||
is_periodic: is_periodic,
|
||||
is_ssh_key: is_ssh_key,
|
||||
crontab: crontab,
|
||||
interval: interval
|
||||
}
|
||||
}
|
||||
|
||||
export default getFields
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user