diff --git a/src/components/AccountCreateUpdateForm/index.vue b/src/components/AccountCreateUpdateForm/index.vue
index 9c316f29f..3bd0ad13b 100644
--- a/src/components/AccountCreateUpdateForm/index.vue
+++ b/src/components/AccountCreateUpdateForm/index.vue
@@ -60,7 +60,7 @@ export default {
]
},
url: '/api/v1/accounts/accounts/',
- form: Object.assign({ 'on_invalid': 'skip' }, this.account || {}),
+ form: Object.assign({ 'on_invalid': 'error' }, this.account || {}),
encryptedFields: ['secret'],
fields: [
[this.$t('assets.Asset'), ['assets']],
diff --git a/src/components/AccountListTable/AccountCreateUpdate.vue b/src/components/AccountListTable/AccountCreateUpdate.vue
index 478e0897a..49888f718 100644
--- a/src/components/AccountListTable/AccountCreateUpdate.vue
+++ b/src/components/AccountListTable/AccountCreateUpdate.vue
@@ -97,16 +97,17 @@ export default {
}
}
this.$axios.post(url, data, {
- disableFlashErrorMsg: true
+ disableFlashErrorMsg: iVisible
}).then((data) => {
this.handleResult(data, null)
+ this.iVisible = iVisible
+ if (!iVisible) {
+ this.$emit('add', true)
+ }
}).catch(error => {
+ this.iVisible = iVisible
this.handleResult(null, error)
})
- this.iVisible = iVisible
- if (!iVisible) {
- this.$emit('add', true)
- }
},
editAccount(form) {
const data = { ...form }
diff --git a/src/components/AccountListTable/AccountList.vue b/src/components/AccountListTable/AccountList.vue
index 720f23268..d95add6ec 100644
--- a/src/components/AccountListTable/AccountList.vue
+++ b/src/components/AccountListTable/AccountList.vue
@@ -321,7 +321,6 @@ export default {
{
name: 'add-template',
title: this.$t('common.TemplateAdd'),
- type: 'primary',
has: !(this.platform || this.asset),
can: () => {
return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot
diff --git a/src/components/AccountListTable/BulkCreateResultDialog.vue b/src/components/AccountListTable/BulkCreateResultDialog.vue
index 860242ea0..0c368dfb9 100644
--- a/src/components/AccountListTable/BulkCreateResultDialog.vue
+++ b/src/components/AccountListTable/BulkCreateResultDialog.vue
@@ -113,4 +113,8 @@ export default {
.color-default {
}
+::v-deep .el-data-table .el-table .el-table__row > td > div > span {
+ white-space: inherit;
+}
+
diff --git a/src/components/FormFields/TextReadonly.vue b/src/components/FormFields/TextReadonly.vue
new file mode 100644
index 000000000..75daefc53
--- /dev/null
+++ b/src/components/FormFields/TextReadonly.vue
@@ -0,0 +1,36 @@
+
+
+ {{ value? trueText : falseText }}
+
+
+
+
+
+
diff --git a/src/components/ListTable/TableAction/ImportTable.vue b/src/components/ListTable/TableAction/ImportTable.vue
index 51d25a1df..a7d8740f9 100644
--- a/src/components/ListTable/TableAction/ImportTable.vue
+++ b/src/components/ListTable/TableAction/ImportTable.vue
@@ -285,7 +285,9 @@ export default {
const data = []
// eslint-disable-next-line prefer-const
for (let [key, value] of Object.entries(errorData)) {
- if (typeof value === 'object') {
+ if (Array.isArray(value)) {
+ value = JSON.stringify(value)
+ } else if (typeof value === 'object') {
value = this.beautifyErrorData(value)
}
let label = this.tableColumnNameMapper[key]
diff --git a/src/components/TableFormatters/EditableInputFormatter.vue b/src/components/TableFormatters/EditableInputFormatter.vue
index fbb119344..e7b8cc33e 100644
--- a/src/components/TableFormatters/EditableInputFormatter.vue
+++ b/src/components/TableFormatters/EditableInputFormatter.vue
@@ -63,9 +63,9 @@ export default {
this.inEditMode = true
},
getCellValue(val) {
- let v
+ let v = ''
if (val && typeof val === 'object') {
- v = val['name'] || val['display_name'] || ''
+ v = val['name'] || val['display_name'] || JSON.stringify(val)
}
return v || val
},
diff --git a/src/i18n/langs/en.json b/src/i18n/langs/en.json
index f830583cb..f18757510 100644
--- a/src/i18n/langs/en.json
+++ b/src/i18n/langs/en.json
@@ -141,7 +141,7 @@
"users": "User",
"Rules": "Rule",
"Action": "Action",
- "ip_group_help_text": "The format is a comma-separated string, * means match all. Example: 192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64",
+ "ip_group_help_text": "* means match all. Example: 192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64",
"apply_login_account": "Apply login account"
},
"applications": {
@@ -1720,7 +1720,9 @@
"UpdateNodeAssetHardwareInfo": "Update node asset hardware information"
},
"users": {
+ "SetStatus": "Set status",
"Set": "Set",
+ "NotSet": "Not set",
"Login": "Users login",
"InviteSuccess": "Invite success",
"inputPhone": "Please enter your mobile phone number",
diff --git a/src/i18n/langs/ja.json b/src/i18n/langs/ja.json
index fc9890b59..ac5a16c70 100644
--- a/src/i18n/langs/ja.json
+++ b/src/i18n/langs/ja.json
@@ -120,7 +120,7 @@
"AccountUsername": "アカウント (ユーザー名)",
"username": "ユーザー名",
"ip_group": "IPグループ",
- "ip_group_help_text": "コンマ区切りの文字列で、 * はすべてにマッチすることを示します。例: 192.168.10.1、192.168.1.0/24、10.1.1-10.1.1. 20、2001:db8:2de::e 13、2001:db8:1a:1110::/64",
+ "ip_group_help_text": "* はすべてにマッチすることを示します。例: 192.168.10.1、192.168.1.0/24、10.1.1-10.1.1. 20、2001:db8:2de::e 13、2001:db8:1a:1110::/64",
"action": "アクション",
"Rules": "ルール",
"Action": "アクション",
@@ -1712,7 +1712,9 @@
"UpdateNodeAssetHardwareInfo": "ノード資産ハードウェア情報の更新"
},
"users": {
+ "SetStatus": "ステータスの設定",
"Set": "設定",
+ "NotSet": "未設定",
"Login": "ユーザー登録",
"InviteSuccess": "成功招待",
"inputPhone": "携帯電話の番号をお願いします",
diff --git a/src/i18n/langs/zh.json b/src/i18n/langs/zh.json
index 28183aaed..25e7fbef9 100644
--- a/src/i18n/langs/zh.json
+++ b/src/i18n/langs/zh.json
@@ -121,7 +121,7 @@
"reviewer": "审批人",
"username": "用户名",
"ip_group": "IP 组",
- "ip_group_help_text": "格式为逗号分隔的字符串, * 表示匹配所有。例如: 192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64",
+ "ip_group_help_text": "* 表示匹配所有。例如: 192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64",
"action": "动作",
"Rules": "规则",
"Action": "动作",
@@ -1708,7 +1708,9 @@
"UpdateNodeAssetHardwareInfo": "更新节点资产硬件信息"
},
"users": {
+ "SetStatus": "设置状态",
"Set": "已设置",
+ "NotSet": "未设置",
"Login": "用户登录",
"InviteSuccess": "邀请成功",
"inputPhone": "请输入手机号码",
diff --git a/src/layout/components/NavHeader/SiteMessages.vue b/src/layout/components/NavHeader/SiteMessages.vue
index 60ee95122..e0554e680 100644
--- a/src/layout/components/NavHeader/SiteMessages.vue
+++ b/src/layout/components/NavHeader/SiteMessages.vue
@@ -62,6 +62,7 @@
:title="currentMsg.content.subject"
:visible.sync="msgDetailVisible"
@cancel="cancelRead"
+ @close="markAsRead([currentMsg])"
@confirm="markAsRead([currentMsg])"
>
diff --git a/src/router/workbench/index.js b/src/router/workbench/index.js
index 2506f8e4e..02e50c0f0 100644
--- a/src/router/workbench/index.js
+++ b/src/router/workbench/index.js
@@ -132,7 +132,7 @@ export default {
}
},
{
- path: 'update',
+ path: ':id/update',
component: () => import('@/views/ops/Job/JobUpdateCreate'),
name: 'JobUpdate',
hidden: true,
@@ -217,11 +217,22 @@ export default {
activeMenu: '/workbench/ops/templates'
}
},
+ {
+ path: 'playbook/create',
+ name: 'PlaybookCreate',
+ hidden: true,
+ component: () => import('@/views/ops/Template/Playbook/PlaybookCreateUpdate'),
+ meta: {
+ title: i18n.t('ops.PlaybookCreate'),
+ permissions: ['ops.add_playbook'],
+ activeMenu: '/workbench/ops/templates'
+ }
+ },
{
path: 'playbook/:id/update',
name: 'PlaybookUpdate',
hidden: true,
- component: () => import('@/views/ops/Template/Playbook/PlaybookUpdate'),
+ component: () => import('@/views/ops/Template/Playbook/PlaybookCreateUpdate'),
meta: {
title: i18n.t('ops.PlaybookUpdate'),
permissions: ['ops.change_playbook'],
diff --git a/src/views/accounts/Account/AccountDetail/Detail.vue b/src/views/accounts/Account/AccountDetail/Detail.vue
index be5021e1d..0e8906d07 100644
--- a/src/views/accounts/Account/AccountDetail/Detail.vue
+++ b/src/views/accounts/Account/AccountDetail/Detail.vue
@@ -196,7 +196,7 @@ export default {
callbacks: Object.freeze({
change: (value) => {
const relationUrl = `/api/v1/accounts/accounts/${this.object.id}/`
- return this.$axios.patch(relationUrl, { su_from: value })
+ return this.$axios.patch(relationUrl, { su_from: value, name: this.object.name })
}
})
}
@@ -205,7 +205,7 @@ export default {
url: `/api/v1/accounts/accounts/${this.object.id}`,
excludes: [
'template', 'privileged', 'secret',
- 'passphrase', 'spec_info'
+ 'passphrase', 'spec_info', 'params'
],
formatters: {
asset: (item, value) => {
@@ -214,6 +214,9 @@ export default {
params: { id: this.object.asset.id }
}
return { value }
+ },
+ su_from: (item, value) => {
+ return {value?.name ? value?.name + `(${value?.username})` : ''}
}
}
}
diff --git a/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretAsset/index.vue b/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretAsset/index.vue
index 7c0594d9b..3cdb886ed 100644
--- a/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretAsset/index.vue
+++ b/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretAsset/index.vue
@@ -143,6 +143,7 @@ export default {
that.select2.disabledValues.splice(i, 1)
}
this.$message.success(this.$tc('common.deleteSuccessMsg'))
+ window.location.reload()
this.$refs.listTable.reloadTable()
}
}
diff --git a/src/views/acl/AssetAcl/AssetAclCreateUpdate.vue b/src/views/acl/AssetAcl/AssetAclCreateUpdate.vue
index 24cdfb5cf..a987f0d9d 100644
--- a/src/views/acl/AssetAcl/AssetAclCreateUpdate.vue
+++ b/src/views/acl/AssetAcl/AssetAclCreateUpdate.vue
@@ -5,9 +5,7 @@
diff --git a/src/views/assets/Platform/PlatformCreateUpdate.vue b/src/views/assets/Platform/PlatformCreateUpdate.vue
index 8425c49a9..a2579a450 100644
--- a/src/views/assets/Platform/PlatformCreateUpdate.vue
+++ b/src/views/assets/Platform/PlatformCreateUpdate.vue
@@ -8,6 +8,7 @@
:fields-meta="fieldsMeta"
:has-detail-in-msg="false"
:initial="initial"
+ :has-reset="false"
:url="url"
/>
@@ -113,6 +114,7 @@ export default {
async updateSuMethods(constrains) {
this.suMethodLimits = constrains['su_methods'] || []
this.updateSuMethodOptions()
+ this.initial.su_method = this.suMethodLimits[0]
},
async setCategories() {
const category = this.$route.query.category
@@ -170,5 +172,17 @@ export default {
width: 100%;
}
}
+>>> .itemMethodKey.el-form-item {
+ display: inline-block;
+ width: 100%;
+ .el-form-item__content {
+ width: 70%;
+ }
+}
+>>> .itemParamsKey.el-form-item {
+ display: inline-block;
+ position: absolute;
+ right: 20px;
+}
diff --git a/src/views/assets/Platform/PlatformList.vue b/src/views/assets/Platform/PlatformList.vue
index 94537e5e5..a67f29cf9 100644
--- a/src/views/assets/Platform/PlatformList.vue
+++ b/src/views/assets/Platform/PlatformList.vue
@@ -24,6 +24,23 @@ export default {
const vm = this
return {
loading: true,
+ nameComponentMap: {
+ host: {
+ icon: 'fa-inbox'
+ },
+ device: {
+ icon: 'fa-microchip'
+ },
+ database: {
+ icon: 'fa-database'
+ },
+ cloud: {
+ icon: 'fa-cloud'
+ },
+ web: {
+ icon: 'fa-globe'
+ }
+ },
tab: {
submenu: [],
activeMenu: 'host'
@@ -86,6 +103,7 @@ export default {
}
},
headerActions: {
+ hasBulkDelete: false,
hasRightActions: true,
createRoute: 'PlatformCreate',
canCreate: () => {
@@ -134,12 +152,13 @@ export default {
},
async setCategories() {
const state = await this.$store.dispatch('assets/getAssetCategories')
- this.tab.submenu = state.assetCategories.map(item => {
- return {
- title: item.label,
- name: item.value
- }
- })
+ for (const item of state.assetCategories) {
+ const name = item.value
+ this.nameComponentMap[name]['name'] = name
+ this.nameComponentMap[name]['title'] = item.label
+ }
+
+ this.tab.submenu = _.toArray(this.nameComponentMap)
}
}
}
diff --git a/src/views/assets/Platform/const.js b/src/views/assets/Platform/const.js
index f8817f5a3..826d29dc0 100644
--- a/src/views/assets/Platform/const.js
+++ b/src/views/assets/Platform/const.js
@@ -32,7 +32,7 @@ export const platformFieldsMeta = (vm) => {
gather_facts_method: {},
push_account_method: {},
push_account_params: {
- label: vm.$t('assets.PushParams')
+ label: ''
},
change_secret_method: {
on: {
@@ -42,7 +42,7 @@ export const platformFieldsMeta = (vm) => {
}
},
change_secret_params: {
- label: vm.$t('assets.ChangeSecretParams'),
+ label: '',
el: {
title: vm.$t('assets.ChangeSecretParams'),
method: 'change_secret_posix'
@@ -125,6 +125,8 @@ export const setAutomations = (vm) => {
_.set(autoFieldsMeta, `${itemMethodKey}.hidden`, (formValue) => {
return !formValue[itemEnabledKey] || !formValue['ansible_enabled']
})
+ // 设置 enableMethod className
+ _.set(autoFieldsMeta, `${itemMethodKey}.attrs.class`, 'itemMethodKey')
// 设置 enableParams Hidden
_.set(autoFieldsMeta, `${itemParamsKey}.hidden`, (formValue) => {
return !formValue[itemEnabledKey] || !formValue['ansible_enabled']
@@ -139,6 +141,10 @@ export const setAutomations = (vm) => {
// 设置 params 类型字段的组件和组件参数
if (needSettingParamsFields.includes(item)) {
+ // 设置 enableParams label
+ _.set(autoFieldsMeta, `${itemParamsKey}.label`, '')
+ // 设置 enableParams className
+ _.set(autoFieldsMeta, `${itemParamsKey}.attrs.class`, 'itemParamsKey')
_.set(autoFieldsMeta, `${itemParamsKey}.component`, AutomationParamsSetting)
_.set(autoFieldsMeta, `${itemParamsKey}.el.method`, initial[itemMethodKey])
}
diff --git a/src/views/assets/const.js b/src/views/assets/const.js
index 2c79473bc..ab51e4ad8 100644
--- a/src/views/assets/const.js
+++ b/src/views/assets/const.js
@@ -29,7 +29,7 @@ export const filterSelectValues = (values) => {
export const assetFieldsMeta = (vm) => {
const platformProtocols = []
const secretTypes = []
- const platformType = vm?.$route.query.type
+ const platformType = vm?.$route.query?.type
return {
address: {
rules: [rules.specialEmojiCheck, rules.RequiredChange]
diff --git a/src/views/ops/Template/Playbook.vue b/src/views/ops/Template/Playbook.vue
index 078ff9b01..9d162fac4 100644
--- a/src/views/ops/Template/Playbook.vue
+++ b/src/views/ops/Template/Playbook.vue
@@ -2,7 +2,6 @@
-
@@ -10,13 +9,11 @@
import GenericListTable from '@/layout/components/GenericListTable'
import UploadDialog from '@/views/ops/Template/Playbook/UploadDialog'
import { ActionsFormatter } from '@/components/TableFormatters'
-import CreatePlaybookDialog from '@/views/ops/Template/Playbook/CreatePlaybookDialog.vue'
export default {
components: {
UploadDialog,
- GenericListTable,
- CreatePlaybookDialog
+ GenericListTable
},
data() {
return {
@@ -49,18 +46,16 @@ export default {
}
},
headerActions: {
+ createRoute: 'PlaybookCreate',
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: true,
- onCreate: () => {
- this.uploadDialogVisible = true
- },
moreCreates: {
callback: (item) => {
switch (item.name) {
case 'create':
- this.createDialogVisible = true
+ this.$router.push({ name: 'PlaybookCreate' })
break
case 'upload':
this.uploadDialogVisible = true
diff --git a/src/views/ops/Template/Playbook/CreatePlaybookDialog.vue b/src/views/ops/Template/Playbook/CreatePlaybookDialog.vue
deleted file mode 100644
index e2b23c9ad..000000000
--- a/src/views/ops/Template/Playbook/CreatePlaybookDialog.vue
+++ /dev/null
@@ -1,79 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/views/ops/Template/Playbook/PlaybookUpdate.vue b/src/views/ops/Template/Playbook/PlaybookCreateUpdate.vue
similarity index 100%
rename from src/views/ops/Template/Playbook/PlaybookUpdate.vue
rename to src/views/ops/Template/Playbook/PlaybookCreateUpdate.vue
diff --git a/src/views/profile/ProfileUpdate/SecretKeyUpdate.vue b/src/views/profile/ProfileUpdate/SecretKeyUpdate.vue
index 382cddf8e..81188bc37 100644
--- a/src/views/profile/ProfileUpdate/SecretKeyUpdate.vue
+++ b/src/views/profile/ProfileUpdate/SecretKeyUpdate.vue
@@ -15,6 +15,7 @@