{{ formatDate(msg.date_created) }}
-
@@ -52,7 +58,7 @@
:title="''"
:close-on-click-modal="false"
:confirm-title="$t('notifications.MarkAsRead')"
- @confirm="markAsRead(currentMsg)"
+ @confirm="markAsRead([currentMsg])"
@cancel="cancelRead"
>
@@ -120,9 +126,26 @@ export default {
return this.$moment(d).fromNow()
}
},
- markAsRead(msg) {
+ oneClickRead(msgs) {
+ this.$confirm(this.$t('notifications.OneClickReadMsg'), this.$t('common.Info'), {
+ type: 'warning',
+ confirmButtonClass: 'el-button--danger',
+ beforeClose: async(action, instance, done) => {
+ if (action !== 'confirm') return done()
+ this.markAsRead(msgs)
+ done()
+ }
+ }).catch(() => {
+ /* 取消*/
+ })
+ },
+ markAsRead(msgs) {
const url = `/api/v1/notifications/site-message/mark-as-read/`
- this.$axios.patch(url, { ids: [msg.id] }).then(res => {
+ const msgIds = []
+ for (const item of msgs) {
+ msgIds.push(item.id)
+ }
+ this.$axios.patch(url, { ids: msgIds }).then(res => {
this.msgDetailVisible = false
this.getMessages()
}).catch(err => {
@@ -178,6 +201,10 @@ export default {
margin-bottom: 0;
padding-top: 10px;
font-size: 16px;
+ .msg-list-all-read-btn {
+ font-size: 12px;
+ float: right;
+ }
}
.el-drawer__body {
diff --git a/src/userviews/users/UserProfile/SecretKeyUpdate.vue b/src/userviews/users/UserProfile/SecretKeyUpdate.vue
new file mode 100644
index 000000000..513c2b4c0
--- /dev/null
+++ b/src/userviews/users/UserProfile/SecretKeyUpdate.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/userviews/users/UserProfile/index.vue b/src/userviews/users/UserProfile/index.vue
index bc9eb7504..f248cfb18 100644
--- a/src/userviews/users/UserProfile/index.vue
+++ b/src/userviews/users/UserProfile/index.vue
@@ -11,6 +11,7 @@ import { GenericDetailPage } from '@/layout/components'
import ProfileInfo from './ProfileInfo'
import ProfileUpdate from './ProfileUpdate'
import PasswordUpdate from './PasswordUpdate'
+import SecretKeyUpdate from './SecretKeyUpdate'
import SSHUpdate from './SSHUpdate'
export default {
@@ -19,6 +20,7 @@ export default {
ProfileInfo,
ProfileUpdate,
PasswordUpdate,
+ SecretKeyUpdate,
SSHUpdate
},
data() {
@@ -55,6 +57,10 @@ export default {
title: this.$t('users.SSHKeySetting'),
name: 'SSHUpdate',
disabled: !this.$store.state.users.profile.can_public_key_auth
+ },
+ {
+ title: this.$t('users.FileEncryptionPassword'),
+ name: 'SecretKeyUpdate'
}
]
},
diff --git a/src/utils/common.js b/src/utils/common.js
index 14dd8495d..8630a788f 100644
--- a/src/utils/common.js
+++ b/src/utils/common.js
@@ -1,4 +1,5 @@
const _ = require('lodash')
+const moment = require('moment')
function getTimeUnits(u) {
const units = {
@@ -169,7 +170,8 @@ export function getDayEnd(now) {
if (!now) {
now = new Date()
}
- return new Date(new Date(now.toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1)
+ const zoneTime = moment(now).utc().endOf('month').format('YYYY-MM-DD HH:mm:ss')
+ return moment(zoneTime).utc().toDate()
}
export function setUrlParam(url, name, value) {
diff --git a/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanCreateUpdate.vue b/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanCreateUpdate.vue
index 830302468..91bb468a2 100644
--- a/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanCreateUpdate.vue
+++ b/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanCreateUpdate.vue
@@ -20,7 +20,7 @@ export default {
[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']]
+ [this.$t('common.Other'), ['recipients', 'comment']]
],
initial: {
type: this.$route.query.type,
@@ -81,7 +81,8 @@ export default {
is_periodic: fields.is_periodic,
password_strategy: fields.password_strategy,
crontab: fields.crontab,
- interval: fields.interval
+ interval: fields.interval,
+ recipients: fields.recipients
},
createSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
updateSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
diff --git a/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/ChangeAuthPlanDetail/AppChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue b/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/ChangeAuthPlanDetail/AppChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue
index 53871540b..c32284179 100644
--- a/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/ChangeAuthPlanDetail/AppChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue
+++ b/src/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/ChangeAuthPlanDetail/AppChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue
@@ -55,8 +55,12 @@ export default {
{
key: this.$t('xpack.ChangeAuthPlan.DateStart'),
value: toSafeLocalDateStr(this.object.date_start)
+ },
+ {
+ key: this.$t('xpack.ChangeAuthPlan.MailRecipient'),
+ value: this.object.recipients ? this.object.recipients.map(
+ i => `${i[0]}` + `${i[1] ? ': ' + this.$t('xpack.ChangeAuthPlan.ContainAttachment') : ''}`).join(', ') : ''
}
-
]
}
}
diff --git a/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue b/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue
index f84470b49..521654f9b 100644
--- a/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue
+++ b/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue
@@ -21,7 +21,7 @@ export default {
[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']]
+ [this.$t('common.Other'), ['recipients', 'comment']]
],
initial: {
password_strategy: 'custom',
@@ -47,7 +47,8 @@ export default {
password_strategy: fields.password_strategy,
ssh_key_strategy: fields.ssh_key_strategy,
crontab: fields.crontab,
- interval: fields.interval
+ interval: fields.interval,
+ recipients: fields.recipients
},
createSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
updateSuccessNextRoute: { name: 'ChangeAuthPlanIndex' },
diff --git a/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue b/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue
index 036683dfa..f20a9df4d 100644
--- a/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue
+++ b/src/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/ChangeAuthPlanExecutionInfo.vue
@@ -51,8 +51,12 @@ export default {
{
key: this.$t('xpack.ChangeAuthPlan.DateStart'),
value: toSafeLocalDateStr(this.object.date_start)
+ },
+ {
+ key: this.$t('xpack.ChangeAuthPlan.MailRecipient'),
+ value: this.object.recipients ? this.object.recipients.map(
+ i => `${i[0]}` + `${i[1] ? ': ' + this.$t('xpack.ChangeAuthPlan.ContainAttachment') : ''}`).join(', ') : ''
}
-
]
}
}
diff --git a/src/views/accounts/ChangeAuthPlan/fields.js b/src/views/accounts/ChangeAuthPlan/fields.js
index 549900d7b..e33110ec5 100644
--- a/src/views/accounts/ChangeAuthPlan/fields.js
+++ b/src/views/accounts/ChangeAuthPlan/fields.js
@@ -127,6 +127,18 @@ function getFields() {
]
}
+ const recipients = {
+ el: {
+ value: [],
+ ajax: {
+ url: '/api/v1/users/users/?fields_size=mini',
+ transformOption: (item) => {
+ return { label: item.name + '(' + item.username + ')', value: item.id }
+ }
+ }
+ }
+ }
+
const nodes = {
label: i18n.t('xpack.Node'),
el: {
@@ -220,7 +232,8 @@ function getFields() {
is_periodic: is_periodic,
is_ssh_key: is_ssh_key,
crontab: crontab,
- interval: interval
+ interval: interval,
+ recipients: recipients
}
}
diff --git a/src/views/applications/DatabaseApp/DatabaseAppList.vue b/src/views/applications/DatabaseApp/DatabaseAppList.vue
index 446ed5f1d..62802486a 100644
--- a/src/views/applications/DatabaseApp/DatabaseAppList.vue
+++ b/src/views/applications/DatabaseApp/DatabaseAppList.vue
@@ -93,6 +93,11 @@ export default {
name: 'Oracle',
title: 'Oracle',
has: this.$store.getters.hasValidLicense
+ },
+ {
+ name: 'SQLServer',
+ title: 'SQLServer',
+ has: this.$store.getters.hasValidLicense
}
]
}
diff --git a/src/views/assets/Asset/AssetList.vue b/src/views/assets/Asset/AssetList.vue
index 91897d462..5e07e1771 100644
--- a/src/views/assets/Asset/AssetList.vue
+++ b/src/views/assets/Asset/AssetList.vue
@@ -51,7 +51,7 @@
+
+
diff --git a/src/views/assets/SystemUser/SystemUserCreateUpdate/CommonUser/vncAndTelnet.vue b/src/views/assets/SystemUser/SystemUserCreateUpdate/CommonUser/vnc.vue
similarity index 100%
rename from src/views/assets/SystemUser/SystemUserCreateUpdate/CommonUser/vncAndTelnet.vue
rename to src/views/assets/SystemUser/SystemUserCreateUpdate/CommonUser/vnc.vue
diff --git a/src/views/assets/SystemUser/SystemUserCreateUpdate/fields.js b/src/views/assets/SystemUser/SystemUserCreateUpdate/fields.js
index 78f09cbb0..7443dbc19 100644
--- a/src/views/assets/SystemUser/SystemUserCreateUpdate/fields.js
+++ b/src/views/assets/SystemUser/SystemUserCreateUpdate/fields.js
@@ -104,6 +104,7 @@ function getFields() {
}
const cmd_filters = {
+ label: this.$t('assets.CmdFilter'),
component: Select2,
el: {
multiple: true,
diff --git a/src/views/assets/SystemUser/SystemUserDetail/Detail.vue b/src/views/assets/SystemUser/SystemUserDetail/Detail.vue
index b77050f2b..c2b5e0710 100644
--- a/src/views/assets/SystemUser/SystemUserDetail/Detail.vue
+++ b/src/views/assets/SystemUser/SystemUserDetail/Detail.vue
@@ -6,7 +6,6 @@
{
- if (row && row.stat) {
- return row.stat?.memory_used.toFixed(1)
+const numTotFixed = (row, type) => {
+ const cur = row.stat?.[type] || ''
+ if (cur instanceof Number && !Number.isInteger(cur)) {
+ return cur.toFixed(1)
}
+ return cur
}
export default {
components: {
@@ -109,17 +111,17 @@ export default {
'stat.cpu_load': {
label: this.$t('sessions.systemCpuLoad'),
width: '120px',
- formatter: numTotFixed
+ formatter: (row) => (numTotFixed(row, 'cpu_load'))
},
'stat.disk_used': {
label: this.$t('sessions.systemDiskUsedPercent'),
width: '120px',
- formatter: numTotFixed
+ formatter: (row) => (numTotFixed(row, 'disk_used'))
},
'stat.memory_used': {
label: this.$t('sessions.systemMemoryUsedPercent'),
width: '120px',
- formatter: numTotFixed
+ formatter: (row) => (numTotFixed(row, 'memory_used'))
},
status: {
label: this.$t('xpack.LoadStatus'),
diff --git a/src/views/settings/Auth/CAS.vue b/src/views/settings/Auth/CAS.vue
index 93c6efaea..07c4cd260 100644
--- a/src/views/settings/Auth/CAS.vue
+++ b/src/views/settings/Auth/CAS.vue
@@ -40,7 +40,7 @@ export default {
el: {
type: 'textarea'
},
- label: this.$t('setting.authCASAttrMap'),
+ label: this.$t('setting.authUserAttrMap'),
rules: [JsonRequired]
}
},
diff --git a/src/views/settings/Auth/SAML2.vue b/src/views/settings/Auth/SAML2.vue
new file mode 100644
index 000000000..da2ade674
--- /dev/null
+++ b/src/views/settings/Auth/SAML2.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
diff --git a/src/views/settings/Auth/index.vue b/src/views/settings/Auth/index.vue
index 0a3ac995f..fafb0c6a1 100644
--- a/src/views/settings/Auth/index.vue
+++ b/src/views/settings/Auth/index.vue
@@ -14,6 +14,7 @@ import DingTalk from './DingTalk'
import FeiShu from './FeiShu'
import WeCom from './WeCom'
import SSO from './SSO'
+import SAML2 from './SAML2'
export default {
name: 'Auth',
@@ -29,7 +30,7 @@ export default {
this.$t('setting.AuthMethod'), [
'AUTH_CAS', 'AUTH_OPENID',
'AUTH_WECOM', 'AUTH_DINGTALK', 'AUTH_FEISHU',
- 'AUTH_RADIUS', 'AUTH_SSO'
+ 'AUTH_RADIUS', 'AUTH_SSO', 'AUTH_SAML2'
]
],
[
@@ -62,6 +63,10 @@ export default {
AUTH_SSO: {
component: SSO
},
+ AUTH_SAML2: {
+ component: SAML2,
+ label: this.$t('setting.SAML2Auth')
+ },
FORGOT_PASSWORD_URL: {
on: {
change([value], updateForm) {
diff --git a/src/views/settings/Security/AuthLimit.vue b/src/views/settings/Security/AuthLimit.vue
index 79c47d285..7073cd488 100644
--- a/src/views/settings/Security/AuthLimit.vue
+++ b/src/views/settings/Security/AuthLimit.vue
@@ -43,22 +43,48 @@ export default {
},
visible: false,
fields: [
- 'SECURITY_LOGIN_LIMIT_COUNT', 'SECURITY_LOGIN_LIMIT_TIME', 'SECURITY_LOGIN_IP_BLACK_LIST',
- 'USER_LOGIN_SINGLE_MACHINE_ENABLED', 'ONLY_ALLOW_EXIST_USER_AUTH',
- 'ONLY_ALLOW_AUTH_FROM_SOURCE'
+ [
+ this.$t('common.UserLoginLimit'),
+ [
+ 'SECURITY_LOGIN_LIMIT_COUNT',
+ 'SECURITY_LOGIN_LIMIT_TIME'
+ ]
+ ],
+ [
+ this.$t('common.IPLoginLimit'),
+ [
+ 'SECURITY_LOGIN_IP_LIMIT_COUNT',
+ 'SECURITY_LOGIN_IP_LIMIT_TIME',
+ 'SECURITY_LOGIN_IP_WHITE_LIST',
+ 'SECURITY_LOGIN_IP_BLACK_LIST'
+ ]
+ ],
+ [
+ this.$t('common.Other'),
+ [
+ 'USER_LOGIN_SINGLE_MACHINE_ENABLED',
+ 'ONLY_ALLOW_EXIST_USER_AUTH',
+ 'ONLY_ALLOW_AUTH_FROM_SOURCE'
+ ]
+ ]
],
successUrl: { name: 'Settings', params: { activeMenu: 'EmailContent' }},
fieldsMeta: {
},
afterGetFormValue(validValues) {
validValues.SECURITY_LOGIN_IP_BLACK_LIST = validValues.SECURITY_LOGIN_IP_BLACK_LIST.toString()
+ validValues.SECURITY_LOGIN_IP_WHITE_LIST = validValues.SECURITY_LOGIN_IP_WHITE_LIST.toString()
return validValues
},
cleanFormValue(value) {
const ipBlackList = value.SECURITY_LOGIN_IP_BLACK_LIST
+ const ipWhiltList = value.SECURITY_LOGIN_IP_WHITE_LIST
if (!Array.isArray(ipBlackList)) {
value.SECURITY_LOGIN_IP_BLACK_LIST = ipBlackList ? ipBlackList.split(',') : []
}
+ if (!Array.isArray(ipWhiltList)) {
+ value.SECURITY_LOGIN_IP_WHITE_LIST = ipWhiltList ? ipWhiltList.split(',') : []
+ }
return value
},
url: '/api/v1/settings/setting/?category=security'
diff --git a/src/views/tickets/RequestApplicationPerm/CreateUpdate.vue b/src/views/tickets/RequestApplicationPerm/CreateUpdate.vue
index ff9589629..533d574b6 100644
--- a/src/views/tickets/RequestApplicationPerm/CreateUpdate.vue
+++ b/src/views/tickets/RequestApplicationPerm/CreateUpdate.vue
@@ -128,6 +128,10 @@ export default {
{
label: 'MariaDB',
value: 'mariadb'
+ },
+ {
+ label: 'SQLServer',
+ value: 'sqlserver'
}
]
},
diff --git a/src/views/tickets/RequestAssetPerm/CreateUpdate.vue b/src/views/tickets/RequestAssetPerm/CreateUpdate.vue
index bc71f7c6c..5ab58932b 100644
--- a/src/views/tickets/RequestAssetPerm/CreateUpdate.vue
+++ b/src/views/tickets/RequestAssetPerm/CreateUpdate.vue
@@ -44,7 +44,7 @@ export default {
},
meta: {
fields: [
- 'apply_assets', 'apply_system_users', 'apply_actions',
+ 'apply_nodes', 'apply_assets', 'apply_system_users', 'apply_actions',
'apply_date_start', 'apply_date_expired'
],
fieldsMeta: {
@@ -53,6 +53,19 @@ export default {
component: AssetPermissionFormActionField,
helpText: this.$t('common.actionsTips')
},
+ apply_nodes: {
+ component: Select2,
+ el: {
+ value: [],
+ ajax: {
+ url: '',
+ transformOption: (item) => {
+ return { label: `${item.full_value}`, value: item.id }
+ }
+ },
+ clearable: true
+ }
+ },
apply_assets: {
type: 'assetSelect',
label: this.$t('perms.Asset'),
@@ -95,14 +108,14 @@ export default {
hidden: (form) => {
const fieldsMeta = this.fieldsMeta.meta.fieldsMeta
fieldsMeta.apply_system_users.el.ajax.url = `/api/v1/assets/system-users/suggestions/?oid=${form['org_id']}&protocol__in=rdp,ssh,vnc,telnet`
- fieldsMeta.apply_assets.el.value = []
fieldsMeta.apply_assets.el.ajax.url = `/api/v1/assets/assets/suggestions/?oid=${form['org_id']}`
+ fieldsMeta.apply_nodes.el.ajax.url = `/api/v1/assets/nodes/suggestions/?oid=${form['org_id']}`
}
}
},
cleanFormValue(value) {
Object.keys(value.meta).forEach((item, index, arr) => {
- if (['apply_assets', 'apply_system_users'].includes(item)) {
+ if (['apply_system_users'].includes(item)) {
if (value.meta[item].length < 1) {
delete value.meta[item]
}
diff --git a/src/views/tickets/RequestAssetPerm/Detail/TicketDetail.vue b/src/views/tickets/RequestAssetPerm/Detail/TicketDetail.vue
index 406e47073..6df2fd008 100644
--- a/src/views/tickets/RequestAssetPerm/Detail/TicketDetail.vue
+++ b/src/views/tickets/RequestAssetPerm/Detail/TicketDetail.vue
@@ -28,6 +28,7 @@ export default {
return {
statusMap: this.object.status === 'open' ? STATUS_MAP['notified'] : STATUS_MAP[this.object.state],
requestForm: {
+ node: this.object.meta.apply_nodes,
asset: this.object.meta.apply_assets,
systemuser: this.object.meta.apply_system_users
},
@@ -69,6 +70,10 @@ export default {
},
specialCardItems() {
return [
+ {
+ key: this.$t('perms.Node'),
+ value: this.object.meta.apply_nodes_display.join(', ')
+ },
{
key: this.$t('tickets.Asset'),
value: this.object.meta.apply_assets_display.join(', ')
@@ -106,6 +111,10 @@ export default {
}
}
},
+ {
+ key: this.$t('perms.Node'),
+ value: this.object.meta.apply_nodes_display.join(', ')
+ },
{
key: this.$t('assets.Asset'),
value: this.object.meta.apply_assets_display.join(', ')
@@ -143,8 +152,12 @@ export default {
window.location.reload()
},
handleApprove() {
- if (this.requestForm.asset.length === 0 || this.requestForm.systemuser.length === 0) {
- return this.$message.error(this.$tc('common.NeedAssetsAndSystemUserErrMsg'))
+ const assetLength = this.requestForm.asset.length
+ const nodeLength = this.requestForm.node.length
+ if (assetLength === 0 && nodeLength === 0) {
+ return this.$message.error(this.$tc('common.SelectAtLeastOneAssetOrNodeErrMsg'))
+ } else if (this.requestForm.systemuser.length === 0) {
+ return this.$message.error(this.$tc('common.RequiredSystemUserErrMsg'))
} else {
this.$axios.put(`/api/v1/tickets/tickets/${this.object.id}/approve/`, {
meta: {}
diff --git a/src/views/xpack/Cloud/Account/AccountList.vue b/src/views/xpack/Cloud/Account/AccountList.vue
index 192f0f765..0b47b7f58 100644
--- a/src/views/xpack/Cloud/Account/AccountList.vue
+++ b/src/views/xpack/Cloud/Account/AccountList.vue
@@ -4,7 +4,7 @@