Merge branch 'dev' into pr@dev@perf_account_template

This commit is contained in:
老广
2023-04-04 09:52:51 +08:00
committed by GitHub
28 changed files with 320 additions and 57 deletions

View File

@@ -46,6 +46,7 @@ export default {
defaultPrivilegedAccounts: ['root', 'administrator'],
iPlatform: {
automation: {},
su_enabled: false,
protocols: [
{
name: 'ssh',
@@ -58,7 +59,7 @@ export default {
encryptedFields: ['secret'],
fields: [
[this.$t('assets.Asset'), ['assets']],
[this.$t('common.Basic'), ['name', 'username', ...this.controlShowField()]],
[this.$t('common.Basic'), ['name', 'username', 'privileged', 'su_from']],
[this.$t('assets.Secret'), [
'secret_type', 'secret', 'ssh_key',
'token', 'access_key', 'passphrase'
@@ -120,7 +121,7 @@ export default {
su_from: {
component: Select2,
hidden: (formValue) => {
return !this.asset?.id
return !this.asset?.id || !this.iPlatform.su_enabled
},
el: {
multiple: false,

View File

@@ -1,5 +1,6 @@
<template>
<Dialog
v-if="iVisible"
:close-on-click-modal="false"
:destroy-on-close="true"
:show-cancel="false"

View File

@@ -201,6 +201,20 @@ export default {
})
}
},
{
name: 'ClearSecret',
title: this.$t('common.ClearSecret'),
can: this.$hasPerm('accounts.change_account'),
type: 'primary',
callback: ({ row }) => {
this.$axios.patch(
`/api/v1/accounts/accounts/clear-secret/`,
{ account_ids: [row.id] }
).then(() => {
this.$message.success(this.$tc('common.ClearSuccessMsg'))
})
}
},
{
name: 'Delete',
title: this.$t('common.Delete'),
@@ -295,6 +309,26 @@ export default {
},
...this.headerExtraActions
],
extraMoreActions: [
{
name: 'ClearSecrets',
title: this.$t('common.ClearSecret'),
type: 'primary',
can: ({ selectedRows }) => {
return selectedRows.length > 0 && vm.$hasPerm('accounts.change_account')
},
callback: function({ selectedRows }) {
const ids = selectedRows.map(v => { return v.id })
this.$axios.patch(
'/api/v1/accounts/accounts/clear-secret/',
{ account_ids: ids }).then(() => {
this.$message.success(this.$tc('common.ClearSuccessMsg'))
}).catch(err => {
this.$message.error(this.$tc('common.bulkClearErrorMsg' + ' ' + err))
})
}.bind(this)
}
],
canBulkDelete: vm.$hasPerm('accounts.delete_account'),
searchConfig: {
getUrlQuery: false,

View File

@@ -27,8 +27,9 @@ export default {
visible: false,
width: '60%',
tableConfig: {
id: 'history_date',
url: `/api/v1/accounts/account-secrets/${this.account.id}/histories/`,
columns: ['secret', 'secret_type', 'history_date'],
columns: ['secret', 'secret_type', 'version', 'history_date'],
columnsMeta: {
secret: {
label: this.$t('assets.Password'),

View File

@@ -155,10 +155,7 @@ export default {
if (isCancel) {
return
}
this.$axios.patch(
url,
{ 'value': treeNode.name }
).then(res => {
this.$axios.patch(url, { 'value': treeNode.name }).then(res => {
let assetsAmount = treeNode.meta.data['assetsAmount']
if (!assetsAmount) {
assetsAmount = 0
@@ -209,6 +206,7 @@ export default {
this.showRMenu('root', event.clientX, event.clientY)
} else if (treeNode && !treeNode.noR) {
this.zTree.selectNode(treeNode)
this.currentNodeId = treeNode.meta.data.id
this.showRMenu('node', event.clientX, event.clientY)
}
},

View File

@@ -10,7 +10,7 @@
>
<el-select
slot="prepend"
v-model="item.name"
:value="item.display_name ? item.display_name : item.name"
:disabled="disableSelect(item)"
class="prepend"
@change="handleProtocolChange($event, item)"

View File

@@ -220,7 +220,7 @@ export default {
}
this.$nextTick(() => {
// 因为elform存在问题这个来清楚验证
const elFormItem = this.$refs.select.elFormItem
const elFormItem = this.$refs.select?.elFormItem
if (elFormItem && elFormItem.clearValidate) {
elFormItem.clearValidate()
}

View File

@@ -117,6 +117,22 @@ export default {
that.$message.success(that.$t('common.RemoveSuccessMsg'))
}
},
onDeleteFail: {
type: Function,
default(error, that) {
let msg = ''
const data = error.response.data
for (const item of Object.keys(data)) {
const value = data[item]
if (value instanceof Array) {
msg = value.join(',')
} else {
msg = value
}
}
that.$message.error(msg)
}
},
performAdd: {
type: Function,
default: (objects, that) => {}
@@ -248,7 +264,9 @@ export default {
removeObject(obj) {
this.performDelete(obj, this).then(
() => this.onDeleteSuccess(obj, this)
)
).catch(error => {
this.onDeleteFail(error, this)
})
},
addObjects() {
const objects = this.$refs.select2.$refs.select.selected.map(item => ({ label: item.label, value: item.value }))

View File

@@ -11,6 +11,8 @@
"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",
"AccountGather": {
"IsSyncAccountLabel": "Synchronize to Asset",
"IsSyncAccountHelpText": "After the collection is completed, the collected account will be synchronized to the asset",
"ExecutionDetail": "Execution detail",
"AccountGatherTaskExecutionList": "Task execution list",
"ExecutionList": "Execution list",
@@ -202,6 +204,7 @@
"NoSQLProtocol": "NoSQL Protocol"
},
"assets": {
"CommentHelpText": "Note: Note information will be hovered and displayed in the user authorization asset tree of Luna page, which can be viewed by ordinary users. Please do not fill in sensitive information.",
"BulkUpdatePlatformHelpText": "Modify only assets of the same type",
"ImportMessage": "Please go to the page of mapping type to import data",
"PushAccount": "Push account",
@@ -497,6 +500,10 @@
"MFAVerify": "Verify MFA",
"CurrentUserVerify": "Verify Current User",
"ViewSecret": "View secret",
"ClearSecret": "Clear secret",
"ClearSuccessMsg": "Clear success",
"bulkClearErrorMsg": "Bulk clear error:",
"Clear": "Clear",
"ConnectWebSocketError": "Connect Websocket failed",
"Nothing": "Nothing",
"Action": "Action",
@@ -604,11 +611,14 @@
"View": "View",
"Yes": "Yes",
"action": "Action",
"SyncSuccessMsg": "Sync success",
"activateSelected": "Activate selected",
"SyncSelected": "Sync selected",
"bulkDeleteErrorMsg": "Bulk delete failed: ",
"bulkDeleteSuccessMsg": "Bulk delete success",
"bulkRemoveErrorMsg": "Bulk remove failed: ",
"bulkRemoveSuccessMsg": "Bulk remove success",
"bulkSyncErrorMsg": "Bulk sync success:",
"SelectAtLeastOneAssetOrNodeErrMsg": "Select at least one asset or node",
"RequiredSystemUserErrMsg": "Required account",
"createBy": "Create by",
@@ -636,6 +646,7 @@
"Success": "Success",
"Failed": "Failed",
"Pending": "Pending",
"ClickCopy": "Click copy",
"imExport": {
"ExportAll": "Export all",
"ExportOnlyFiltered": "Export only filtered",
@@ -933,6 +944,7 @@
"AssetResultDetail": "Asset result",
"total": "Total",
"Variable": "Variable",
"Description": "Description",
"PlaybookDetail": "Playbook detail",
"DryRun": "Dry run",
"SelectAdhoc": "Select Adhoc",
@@ -970,6 +982,7 @@
"Run": "Run",
"NewFile": "New file",
"Job": "Job",
"JobName": "Job name",
"Type": "Type",
"running": "Runing",
"ScrollToTop": "Scroll to top",
@@ -1007,11 +1020,15 @@
},
"perms": {
"": "",
"AllAccounts": "All accounts",
"ManualInput": "Manual input",
"SameAccount": "Same account",
"SpecifyAccounts": "Specify accounts",
"AccountsHelp": "All accounts: accounts exists on the asset; Specify accounts: specify the user name of the account under the assetManual input: username/password; Same account: The account username name same with login user",
"AllAccounts": "All accounts",
"AllAccountTip": "All accounts added on the asset",
"ManualAccount": "Manual account",
"ManualAccountTip": "Login manually enter user name/password",
"SameAccount": "Same account",
"SameAccountTip": "Account with the same user name of the authorized person",
"SpecAccount": "Specify account",
"SpecAccountTip": "Specify user name and select authorized account",
"Input": "Input",
"permAccount": "Accounts",
"Actions": "Actions",
@@ -1193,7 +1210,7 @@
"OperateLog": "Operation Logs",
"PasswordChangeLog": "Password Update Logs",
"Perms": "Permissions",
"PersonalInformationImprovement": "PersonalInformationImprovement",
"PersonalInformationImprovement": "Personal Information Improvement",
"PlatformCreate": "Platform create",
"PlatformDetail": "Platform detail",
"PlatformList": "Platforms",

View File

@@ -11,6 +11,8 @@
"PleaseClickLeftApplicationToViewApplicationAccount": "アカウントのリストを適用して、左側のアプリケーションをクリックして表示します",
"PleaseClickLeftAssetToViewGatheredUser": "ユーザーリストを収集し、左側の資産をクリックして表示します。",
"AccountGather": {
"IsSyncAccountLabel": "資産への同期化",
"IsSyncAccountHelpText": "収集が完了すると、収集したアカウントが資産に同期されます",
"ExecutionDetail": "タスクの詳細",
"AccountGatherTaskExecutionList": "タスク実行リスト",
"ExecutionList": "実行リスト",
@@ -202,6 +204,7 @@
"NoSQLProtocol": "非リレーショナルデータベース"
},
"assets": {
"CommentHelpText": "注意コメント情報はLunaページのユーザー認可資産ツリーに表示されます。一般ユーザーは表示できますので、機密情報を記入しないでください。",
"BulkUpdatePlatformHelpText": "同じタイプの資産のみ変更",
"ImportMessage": "ミラータイプのページにデータをインポートしてください",
"PushAccount": "アカウント情報をプッシュ",
@@ -493,7 +496,9 @@
"ApprovaLevel": "承認情報",
"MFAVerify": "MFAの検証",
"CurrentUserVerify": "現在のユーザー検証",
"ViewSecret": "パスワードの確認",
"ViewSecret": "暗号文の表示",
"ClearSecret": "暗号文の削除",
"Clear": "クリア",
"ConnectWebSocketError": "Webソケット接続に失敗しました",
"Action": "アクション",
"RequestTickets": "ワークオーダーを申請する",
@@ -582,6 +587,8 @@
"QuickUpdate": "クイックアップデート",
"QuickSelect": "クイック選択",
"RemoveSuccessMsg": "削除に成功しました",
"ClearSuccessMsg": "クリアに成功しました",
"bulkClearErrorMsg": "クリアに失敗しました: ",
"Reset": "リセット",
"Search": "検索",
"Select": "選択",
@@ -604,6 +611,9 @@
"action": "アクション",
"User": "ユーザー",
"activateSelected": "選択した活性化",
"SyncSuccessMsg": "同期に成功しました",
"SyncSelected": "選択した同期",
"bulkSyncErrorMsg": "一括同期に失敗しました:",
"bulkDeleteErrorMsg": "一括削除に失敗しました:",
"bulkDeleteSuccessMsg": "一括削除に成功しました",
"bulkRemoveErrorMsg": "一括削除に失敗しました:",
@@ -638,6 +648,7 @@
"Status": "ステータス",
"InputEmailAddress": "正しいメールアドレスを入力してください",
"Receivers": "受取人",
"ClickCopy": "クリックしてコピー",
"imExport": {
"ExportAll": "すべてをエクスポート",
"ExportOnlyFiltered": "検索結果のみエクスポート",
@@ -925,6 +936,7 @@
"AssetResultDetail": "アセットの結果",
"total": "合計",
"Variable": "変数",
"Description": "説明",
"PlaybookDetail": "Playbook 詳細",
"DryRun": "テスト走行",
"SelectAdhoc": "コマンドを選択",
@@ -963,6 +975,7 @@
"SaveCommandSuccess": "保存コマンドが成功しました",
"NewFile": "新しいファイルを作成する",
"Job": "手術",
"JobName": "ジョブ名",
"SUCCESS": "成功",
"Type": "タイプ",
"running": "ランニング",
@@ -1003,11 +1016,15 @@
},
"perms": {
"": "",
"AllAccounts": "すべてのアカウント",
"ManualInput": "手動入力",
"SameAccount": "同じ名前のアカウント",
"SpecifyAccounts": "入力の指定",
"AccountsHelp": "すべてのアカウント: アカウントはアセットに存在します。 アカウントの指定: 資産の下のアカウントのユーザー名を指定します。手入力: ユーザー名/パスワード; 同一アカウント:ログインユーザーと同じアカウントのユーザー名",
"AllAccounts": "すべてのアカウント",
"AllAccountTip": "資産に追加されたすべてのアカウント",
"ManualInput": "手動入力",
"ManualAccountTip": "ログイン時のユーザー名/パスワードの手動入力",
"SameAccount": "同じ名前のアカウント",
"SameAccountTip": "権限受領者のユーザー名と同じアカウント",
"SpecAccount": "入力の指定",
"SpecAccountTip": "入力の指定権限アカウントの選択",
"Input": "入力",
"permAccount": "認定アカウント",
"Actions": "アクション",

View File

@@ -93,6 +93,8 @@
"Username": "用户名"
},
"AccountGather": {
"IsSyncAccountLabel": "同步到资产",
"IsSyncAccountHelpText": "收集完成后会把收集的账号同步到资产",
"AccountGather": "账号收集",
"ExecutionList": "执行列表",
"AccountGatherList": "收集任务",
@@ -204,8 +206,9 @@
"NoSQLProtocol": "非关系数据库"
},
"assets": {
"CommentHelpText": "注意:备注信息会在 Luna 页面的用户授权资产树中进行悬停显示,普通用户可以查看,请不要填写敏感信息。",
"BulkUpdatePlatformHelpText": "只修改相同类型的资产",
"ImportMessage": "请前往对类型的页面导入数据",
"ImportMessage": "请前往对类型的页面导入数据",
"PushAccount": "推送账号",
"SSHPort": "SSH 端口",
"AuthUsername": "使用用户名认证",
@@ -509,7 +512,9 @@
"ApprovaLevel": "审批信息",
"MFAVerify": "验证 MFA",
"CurrentUserVerify": "验证当前用户",
"ViewSecret": "查看密",
"ViewSecret": "查看密",
"ClearSecret": "清除密文",
"Clear": "清除",
"ConnectWebSocketError": "连接 WebSocket 失败",
"Action": "动作",
"RequestTickets": "申请工单",
@@ -602,6 +607,9 @@
"QuickUpdate": "快速更新",
"QuickSelect": "快速选择",
"RemoveSuccessMsg": "移除成功",
"ClearSuccessMsg": "清除成功",
"bulkClearErrorMsg": "批量清除失败:",
"SyncSuccessMsg": "同步成功",
"Reset": "重置",
"Search": "搜索",
"Select": "选择",
@@ -625,9 +633,11 @@
"action": "动作",
"User": "用户",
"activateSelected": "激活所选",
"SyncSelected": "同步所选",
"bulkDeleteErrorMsg": "批量删除失败: ",
"bulkDeleteSuccessMsg": "批量删除成功",
"bulkRemoveErrorMsg": "批量移除失败: ",
"bulkSyncErrorMsg": "批量同步失败: ",
"SelectAtLeastOneAssetOrNodeErrMsg": "资产或者节点至少选择一项",
"RequiredSystemUserErrMsg": "请选择账号",
"bulkRemoveSuccessMsg": "批量移除成功",
@@ -659,6 +669,7 @@
"Status": "状态",
"InputEmailAddress": "请输入正确的邮箱地址",
"Receivers": "接收人",
"ClickCopy": "点击复制",
"imExport": {
"ExportAll": "导出所有",
"ExportOnlyFiltered": "仅导出搜索结果",
@@ -898,6 +909,7 @@
"DryRun": "测试运行",
"Language": "语言",
"Job": "作业",
"JobName": "作业名称",
"Command": "命令",
"Material": "内容",
"Type": "类型",
@@ -988,6 +1000,7 @@
"State": "状态",
"LastPublishedTime": "最后发布时间",
"Variable": "变量",
"Description": "描述",
"Module": "模块",
"Asset": "资产",
"Plan": "计划",
@@ -1595,9 +1608,9 @@
},
"tickets": {
"ApplyAsset": "申请资产",
"LoginConfirm": "用户登录复",
"CommandConfirm": "命令复",
"LoginAssetConfirm": "资产登录复",
"LoginConfirm": "用户登录复",
"CommandConfirm": "命令复",
"LoginAssetConfirm": "资产登录复",
"RelevantAssignees": "相关受理人",
"OneAssigneeType": "一级受理人类型",
"OneAssignee": "一级受理人",

View File

@@ -142,6 +142,24 @@ export default {
}
})
},
{
title: this.$t('common.ClearSecret'),
attrs: {
type: 'primary',
label: this.$t('common.Clear'),
disabled: !vm.$hasPerm('accounts.change_account')
},
callbacks: Object.freeze({
click: () => {
this.$axios.patch(
'/api/v1/accounts/accounts/clear-secret/',
{ account_ids: [this.object.id] }
).then(() => {
this.$message.success(this.$tc('common.ClearSuccessMsg'))
})
}
})
},
{
title: this.$t('assets.UserSwitchFrom'),
type: 'updateSelect',

View File

@@ -73,10 +73,11 @@ export default {
type: 'primary',
callback: ({ row }) => {
this.$axios.post(
`/api/v1/accounts/gathered-accounts/${row.id}/sync/`,
`/api/v1/accounts/gathered-accounts/sync-accounts/`,
{ gathered_account_ids: [row.id] }
).then(res => {
this.$message.success(this.$tc('common.updateSuccessMsg'))
}).catch(res => {
this.$message.success(this.$tc('common.SyncSuccessMsg'))
}).catch(() => {
})
}
}
@@ -86,14 +87,35 @@ export default {
}
},
headerActions: {
hasLeftActions: false,
hasCreate: false,
hasImport: false,
hasExport: false,
hasBulkDelete: false,
searchConfig: {
exclude: ['asset'],
options: []
}
},
extraMoreActions: [
{
name: 'SyncSelected',
title: this.$t('common.SyncSelected'),
type: 'primary',
can: ({ selectedRows }) => {
return selectedRows.length > 0 && vm.$hasPerm('accounts.add_gatheredaccount')
},
callback: function({ selectedRows }) {
const ids = selectedRows.map(v => { return v.id })
this.$axios.post(
`/api/v1/accounts/gathered-accounts/sync-accounts/`,
{ gathered_account_ids: ids }
).then(() => {
this.$message.success(this.$tc('common.SyncSuccessMsg'))
}).catch(err => {
this.$message.error(this.$tc('common.bulkSyncErrorMsg' + ' ' + err))
})
}.bind(this)
}
]
}
}
}

View File

@@ -15,11 +15,16 @@ export default {
fields: [
[this.$t('common.Basic'), ['name', 'nodes']],
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
[this.$t('common.Other'), ['is_active', 'comment']]
[this.$t('common.Other'), ['is_sync_account', 'is_active', 'comment']]
],
url: '/api/v1/accounts/gather-account-automations/',
hasDetailInMsg: false,
fieldsMeta: {
is_sync_account: {
type: 'switch',
label: this.$t('accounts.AccountGather.IsSyncAccountLabel'),
helpText: this.$t('accounts.AccountGather.IsSyncAccountHelpText')
},
crontab: {
component: CronTab,
hidden: (formValue) => {

View File

@@ -43,9 +43,17 @@ export default {
},
{
key: this.$t('acl.CommandGroup'),
value: this.object.command_groups.map((item) => { return item.name }).join(', ')
value: this.object.command_groups.map((item) => item.name).join(', ')
},
'comment'
{
key: this.$t('acl.action'),
value: this.object.action?.label
},
(this.object.action?.value === 'review' && {
key: this.$t('acl.reviewer'),
value: this.object?.reviewers.map((item) => item?.name).join(', ')
}),
'priority', 'is_active', 'comment'
]
}
},

View File

@@ -78,6 +78,17 @@ export default {
})
}
return this.$axios[submitMethod](url, values)
},
onPerformSuccess(res, method) {
const nextRoute = this.$router.push({ name: 'AssetList', params: { extraQuery: { order: '-date_updated' }}})
switch (method) {
case 'post':
this.$message.success(this.$tc('common.createSuccessMsg'))
return nextRoute
case 'put':
this.$message.success(this.$tc('common.updateSuccessMsg'))
return nextRoute
}
}
}
}
@@ -140,8 +151,15 @@ export default {
},
async setPlatformConstrains() {
const { platform } = this
let protocols = platform?.protocols || []
protocols = protocols.map(i => {
if (i.name === 'http') {
i.display_name = 'http(s)'
}
return i
})
const protocolChoices = this.defaultConfig.fieldsMeta.protocols.el.choices
protocolChoices.splice(0, protocolChoices.length, ...platform.protocols)
protocolChoices.splice(0, protocolChoices.length, ...protocols)
this.defaultConfig.fieldsMeta.accounts.el.platform = platform
const hiddenCheckFields = ['protocols', 'domain']

View File

@@ -5,12 +5,18 @@
</el-link>
<div v-else class="accounts">
<el-table :data="accounts" style="width: 100%">
<el-table-column :label="$tc('assets.Username')" prop="username" width="180" />
<el-table-column :label="$tc('assets.Name')" prop="name" />
<el-table-column :label="$tc('assets.Username')" prop="username" />
<el-table-column :label="$tc('assets.Privileged')" prop="privileged">
<template v-slot="scope">
<i :class="scope.row['privileged'] ? 'fa-check' : ''" class="fa text-primary" />
</template>
</el-table-column>
<el-table-column :label="$tc('common.TemplateAdd')" prop="template">
<template v-slot="scope">
<i :class="scope.row['template'] ? 'fa-check' : ''" class="fa text-primary" />
</template>
</el-table-column>
<el-table-column :label="$tc('common.Actions')" align="right" class-name="buttons" fixed="right" width="135">
<template v-slot="scope">
<el-button icon="el-icon-minus" size="mini" type="danger" @click="removeAccount(scope.row)" />

View File

@@ -6,9 +6,11 @@
<ListTable ref="ListTable" :header-actions="iHeaderActions" :table-config="iTableConfig" />
<PlatformDialog :category="category" :visible.sync="showPlatform" />
<AssetBulkUpdateDialog
v-if="updateSelectedDialogSetting.visible"
:visible.sync="updateSelectedDialogSetting.visible"
v-bind="updateSelectedDialogSetting"
:category="category"
@update="handleAssetBulkUpdate"
/>
<GatewayDialog
:cell="GatewayCell"
@@ -65,6 +67,11 @@ export default {
optionInfo: {
type: Object,
default: () => ({})
},
// url中需要添加额外的参数
extraQuery: {
type: Object,
default: () => ({})
}
},
data() {
@@ -91,6 +98,7 @@ export default {
}
vm.$router.push(route)
}
const extraQuery = this.$route.params?.extraQuery || {}
return {
showPlatform: false,
GatewayPort: 0,
@@ -102,6 +110,10 @@ export default {
app: 'assets',
resource: 'asset'
},
extraQuery: {
...extraQuery,
...this.extraQuery
},
columnsExclude: ['spec_info', 'auto_info'],
columnsShow: {
min: ['name', 'address', 'actions'],
@@ -279,6 +291,11 @@ export default {
optionInfo(iNew) {
this.$set(this.defaultConfig.columnsMeta.info.formatterArgs, 'info', iNew)
}
},
methods: {
handleAssetBulkUpdate() {
this.$refs.ListTable.reloadTable()
}
}
}
</script>

View File

@@ -39,8 +39,7 @@ export default {
category_type: ['host', 'linux'],
automation: {
ansible_enabled: true
},
su_method: ''
}
},
fields: [
[this.$t('common.Basic'), [
@@ -133,12 +132,20 @@ export default {
this.defaultOptions = constraints
const fieldsCheck = ['domain_enabled', 'su_enabled']
let protocols = constraints?.protocols || []
protocols = protocols.map(i => {
if (i.name === 'http') {
i.display_name = 'http(s)'
}
return i
})
for (const field of fieldsCheck) {
const disabled = constraints[field] === false
this.initial[field] = !disabled
_.set(this.fieldsMeta, `${field}.el.disabled`, disabled)
}
this.fieldsMeta.protocols.el.choices = constraints['protocols'] || []
this.fieldsMeta.protocols.el.choices = protocols
if (constraints['charset_enabled'] === false) {
this.fieldsMeta.charset.hidden = () => true

View File

@@ -32,7 +32,7 @@ export const assetFieldsMeta = (vm) => {
const platformType = vm?.$route.query.platform_type
return {
address: {
rules: [rules.specialEmojiCheck]
rules: [rules.specialEmojiCheck, rules.RequiredChange]
},
protocols: {
component: ProtocolSelector,
@@ -132,6 +132,9 @@ export const assetFieldsMeta = (vm) => {
},
url: {
label: 'url'
},
comment: {
helpText: i18n.t('assets.CommentHelpText')
}
}
}

View File

@@ -24,12 +24,12 @@ export default {
tableConfig: {
url: '/api/v1/ops/job-executions/',
columns: [
'id', 'material', 'job_type', 'is_finished', 'is_success', 'time_cost', 'date_created', 'actions'
'id', 'job', 'material', 'job_type', 'is_finished', 'is_success', 'time_cost', 'date_created', 'actions'
],
columnsShow: {
min: ['material', 'actions'],
default: [
'id', 'material', 'job_type', 'is_finished', 'is_success', 'time_cost', 'date_created', 'actions'
'id', 'job', 'material', 'job_type', 'is_finished', 'is_success', 'time_cost', 'date_created', 'actions'
]
},
columnsMeta: {
@@ -49,6 +49,12 @@ export default {
return '-'
}
},
job: {
label: this.$t('ops.JobName'),
formatter: (row) => {
return <span>{row.job?.name || '-'}</span>
}
},
material: {
width: '160px'
},

View File

@@ -35,6 +35,12 @@ export default {
url: `/api/v1/ops/adhocs/`,
columns: ['name', 'module', 'args', 'comment', 'actions'],
columnsMeta: {
name: {
title: this.$tc('common.Name'),
formatter: (row) => {
return row?.name || '-'
}
},
actions: {
formatter: ActionsFormatter,
formatterArgs: {

View File

@@ -4,20 +4,29 @@
:show-confirm="false"
:title="title"
:visible.sync="iVisible"
class="help-dialog"
width="50%"
top="1vh"
>
<p>{{ $t('ops.VariableHelpText') }}</p>
<el-form>
<el-form-item v-for="(val,key,index) in variables" :key="index" :label="key+':'">
<span>{{ val }}</span>
</el-form-item>
</el-form>
<table class="help-table" border="1">
<tr>
<th>{{ $tc('ops.Variable') }}</th>
<th>{{ $tc('ops.Description') }}</th>
</tr>
<tr v-for="(val, key, index) in variables" :key="index">
<td class="item-td text-link" :title="$tc('common.ClickCopy')" @click="onCopy(key)">
<label class="item-label">{{ key }}</label>
</td>
<td><span>{{ val }}</span></td>
</tr>
</table>
</Dialog>
</template>
<script>
import { Dialog } from '@/components'
import { copy } from '@/utils/common'
export default {
components: {
@@ -49,10 +58,35 @@ export default {
this.$axios.get('/api/v1/ops/variables/help').then((data) => {
this.variables = data
})
},
methods: {
onCopy(key) {
copy(key)
}
}
}
</script>
<style scoped>
<style>
.help-dialog.dialog .el-dialog__footer {
border-top: none;
padding: 8px;
}
</style>
<style lang="scss" scoped>
.help-table {
width: 100%;
border-collapse: collapse;
border: 1px solid #dee2e6;
&>>> th, td {
height: 40px;
padding: 0 8px;
text-align: left;
}
&>>> .item-td, .item-label {
cursor: pointer;
color: var(--color-primary);
}
}
</style>

View File

@@ -24,10 +24,12 @@
:value="specAccountsInput"
@change="handleTagChange"
/>
<el-button size="small" type="primary" style="margin-left: 10px" @click="showAccountTemplateDialog=true">
{{ $t('common.TemplateAdd') }}
</el-button>
{{ $t('common.TemplateHelpText') }}
<span v-if="showAddTemplate">
<el-button size="small" type="primary" style="margin-left: 10px" @click="showAccountTemplateDialog=true">
{{ $t('common.TemplateAdd') }}
</el-button>
{{ addTemplateHelpText }}
</span>
</el-form-item>
</div>
@@ -71,6 +73,16 @@ export default {
oid: {
type: String,
default: ''
},
showAddTemplate: {
type: Boolean,
default: true
},
addTemplateHelpText: {
type: String,
default() {
return this.$t('common.TemplateHelpText')
}
}
},
data() {

View File

@@ -21,8 +21,8 @@ export default {
tableConfig: {
url: `/api/v1/terminal/session-join-records/?session=${this.object.id}`,
columns: [
'joiner_display', 'verify_code', 'reason', 'is_success', 'is_finished',
'date_joined', 'date_left', 'org_name'
'joiner_display', 'reason', 'is_success', 'is_finished',
'date_joined', 'date_left', 'org_name', 'action_permission'
],
columnsShow: {
min: ['joiner_display', 'is_success', 'reason'],

View File

@@ -81,7 +81,6 @@ export default {
label: this.$t('sessions.target')
},
command_amount: {
label: this.$t('sessions.command'),
width: '90px'
},
login_from: {

View File

@@ -92,7 +92,9 @@ export default {
},
apply_accounts: {
component: AccountFormatter,
el: {}
el: {
showAddTemplate: false
}
},
org_id: {
component: Select2,

View File

@@ -20,7 +20,7 @@
<Select2 v-model="requestForm.assets" v-bind="assetSelect2" style="width: 50% !important" />
</el-form-item>
<el-form-item :label="$tc('perms.Account')" :rules="isRequired">
<AccountFormatter v-model="requestForm.accounts" style="width: 50% !important" />
<AccountFormatter v-model="requestForm.accounts" :show-add-template="false" style="width: 50% !important" />
</el-form-item>
<el-form-item :label="$tc('common.DateStart')" required>
<el-date-picker