mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-15 14:24:39 +00:00
@@ -58,7 +58,7 @@ export function JobUploadFile(form) {
|
||||
url: '/api/v1/ops/jobs/upload/',
|
||||
method: 'post',
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
timeout: 10 * 60 * 1000,
|
||||
timeout: 60 * 60 * 1000,
|
||||
data: form
|
||||
})
|
||||
}
|
||||
|
||||
@@ -392,9 +392,18 @@ export default {
|
||||
can: this.$hasPerm('accounts.delete_account'),
|
||||
type: 'primary',
|
||||
callback: ({ row }) => {
|
||||
this.$axios.delete(`/api/v1/accounts/accounts/${row.id}/`).then(() => {
|
||||
this.$message.success(this.$tc('common.deleteSuccessMsg'))
|
||||
this.$refs.ListTable.reloadTable()
|
||||
const msg = this.$t('accounts.AccountDeleteConfirmMsg')
|
||||
this.$confirm(msg, this.$tc('common.Info'), {
|
||||
type: 'warning',
|
||||
confirmButtonClass: 'el-button--danger',
|
||||
beforeClose: async(action, instance, done) => {
|
||||
if (action !== 'confirm') return done()
|
||||
this.$axios.delete(`/api/v1/accounts/accounts/${row.id}/`).then(() => {
|
||||
done()
|
||||
this.$refs.ListTable.reloadTable()
|
||||
this.$message.success(this.$tc('common.deleteSuccessMsg'))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ const {
|
||||
addMessageToActiveChat,
|
||||
newChatAndAddMessageById,
|
||||
removeLoadingMessageInChat,
|
||||
removeLoadingAndAddMessageToChat,
|
||||
updateChaMessageContentById,
|
||||
addTemporaryLoadingToChat
|
||||
} = useChat()
|
||||
@@ -120,12 +119,11 @@ export default {
|
||||
}
|
||||
},
|
||||
onChatMessage(data) {
|
||||
if (!data.message.content && data.conversation_id) {
|
||||
if (data.conversation_id) {
|
||||
setLoading(true)
|
||||
removeLoadingAndAddMessageToChat(data)
|
||||
removeLoadingMessageInChat()
|
||||
this.currentConversationId = data.conversation_id
|
||||
} else {
|
||||
updateChaMessageContentById(data.message.id, data.message.content)
|
||||
updateChaMessageContentById(data.message.id, data)
|
||||
}
|
||||
if (data.message?.type === 'finish') {
|
||||
setLoading(false)
|
||||
|
||||
@@ -59,13 +59,8 @@ export function useChat() {
|
||||
addChatMessageById(chat)
|
||||
}
|
||||
|
||||
const removeLoadingAndAddMessageToChat = (chat) => {
|
||||
store.commit('chat/removeLoadingMessageInChat')
|
||||
store.commit('chat/addMessageToActiveChat', chat)
|
||||
}
|
||||
|
||||
const updateChaMessageContentById = (id, content) => {
|
||||
store.commit('chat/updateChaMessageContentById', { id, content })
|
||||
const updateChaMessageContentById = (id, data) => {
|
||||
store.commit('chat/updateChaMessageContentById', { id, data })
|
||||
pageScroll('scrollRef')
|
||||
}
|
||||
|
||||
@@ -78,7 +73,6 @@ export function useChat() {
|
||||
addMessageToActiveChat,
|
||||
newChatAndAddMessageById,
|
||||
removeLoadingMessageInChat,
|
||||
removeLoadingAndAddMessageToChat,
|
||||
addChatMessageById,
|
||||
addTemporaryLoadingToChat,
|
||||
updateChaMessageContentById
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"AddAccountResult": "Add account result",
|
||||
"AutoPush": "Auto Push",
|
||||
"GeneralAccounts": "General Accounts",
|
||||
"VirtualAccounts": "Virtual Accounts"
|
||||
"VirtualAccounts": "Virtual Accounts",
|
||||
"AccountDeleteConfirmMsg": "Delete account, do you want to continue?"
|
||||
},
|
||||
"acl": {
|
||||
"CommandFilterACLHelpMsg": "You can control whether commands can be executed on assets. Based on the rules, certain commands can be allowed while others are prohibited.",
|
||||
@@ -1757,6 +1758,7 @@
|
||||
"LDAPServerInfo": "LDAP Server",
|
||||
"LDAPUser": "LDAP User",
|
||||
"ChatAI": "Chat ai",
|
||||
"Example": "Example: {example}",
|
||||
"InsecureCommandAlert": "Insecure command alert",
|
||||
"helpText": {
|
||||
"TempPassword": "For a while, there is a period of 300 seconds, failure immediately after use",
|
||||
@@ -2110,7 +2112,7 @@
|
||||
"passwordWillExpiredPrefixMsg": "The password will expire in ",
|
||||
"passwordWillExpiredSuffixMsg": " days.Please change your password as soon as possible.",
|
||||
"dateLastLogin": "Date last login",
|
||||
"AddAllMembersWarningMsg": "Are you sure you want to add all members"
|
||||
"AddAllMembersWarningMsg": "Are you sure you want to add all members?"
|
||||
},
|
||||
"notifications": {
|
||||
"MessageType": "Message Type",
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"AddAccountResult": "账号批量添加结果",
|
||||
"AutoPush": "自動プッシュ",
|
||||
"GeneralAccounts": "一般アカウント",
|
||||
"VirtualAccounts": "仮想アカウント"
|
||||
"VirtualAccounts": "仮想アカウント",
|
||||
"AccountDeleteConfirmMsg": "アカウントを削除します,続行しますか?"
|
||||
},
|
||||
"acl": {
|
||||
"CommandFilterACLHelpMsg": "コマンドフィルタリングを使用すると、コマンドがアセット上で実行されるかどうかを制御できます。ルールに基づいて、特定のコマンドは許可され、他のコマンドは禁止されることがあります。",
|
||||
@@ -1763,6 +1764,7 @@
|
||||
"LDAPServerInfo": "LDAPサーバー",
|
||||
"LDAPUser": "LDAPユーザー",
|
||||
"ChatAI": "チャットAI",
|
||||
"Example": "例: {example}",
|
||||
"helpText": {
|
||||
"TempPassword": "一時パスワードの有効期間は300秒で、使用後すぐに失効します",
|
||||
"ApiKeyList": "Api keyを使用してリクエストヘッダに署名します。リクエストのヘッダごとに異なります。使用ドキュメントを参照してください",
|
||||
@@ -2099,7 +2101,7 @@
|
||||
"passwordExpired": "パスワードが期限切れです",
|
||||
"passwordWillExpiredPrefixMsg": "パスワードはまもなく",
|
||||
"passwordWillExpiredSuffixMsg": "期限が切れた後、できるだけ早くパスワードを変更してください。",
|
||||
"AddAllMembersWarningMsg": "すべてのメンバーを追加してもよろしいですか"
|
||||
"AddAllMembersWarningMsg": "すべてのメンバーを追加してもよろしいですか?"
|
||||
},
|
||||
"notifications": {
|
||||
"MessageType": "メッセージタイプ",
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"PleaseClickLeftAssetToViewGatheredUser": "收集用户列表,点击左侧资产进行查看",
|
||||
"AutoCreate": "自动创建",
|
||||
"AccountExportTips": "导出信息中包含账号密文涉及敏感信息,导出的格式为一个加密的zip文件(若没有设置加密密码,请前往个人信息中设置文件加密密码)。",
|
||||
"AccountDeleteConfirmMsg": "删除账号,是否继续?",
|
||||
"AccountPush": {
|
||||
"WindowsPushHelpText": "windows 资产暂不支持推送密钥",
|
||||
"AccountPushList": "账号推送",
|
||||
@@ -1752,6 +1753,7 @@
|
||||
"LDAPServerInfo": "LDAP 服务器",
|
||||
"LDAPUser": "LDAP 用户",
|
||||
"ChatAI": "智能问答",
|
||||
"Example": "例: {example}",
|
||||
"helpText": {
|
||||
"TempPassword": "临时密码有效期为 300 秒,使用后立刻失效",
|
||||
"ApiKeyList": "使用 Api key 签名请求头进行认证,每个请求的头部是不一样的, 相对于 Token 方式,更加安全,请查阅文档使用;<br>为降低泄露风险,Secret 仅在生成时可以查看, 每个用户最多支持创建 10 个",
|
||||
@@ -1965,7 +1967,7 @@
|
||||
"KokoSettingUpdate": "Koko 配置设置",
|
||||
"UserSetting": "偏好设置",
|
||||
"AllMembers": "全部成员",
|
||||
"AddAllMembersWarningMsg": "你确定要添加全部成员",
|
||||
"AddAllMembersWarningMsg": "你确定要添加全部成员?",
|
||||
"UnbindHelpText": "本地用户为此认证来源用户,无法解绑",
|
||||
"SetStatus": "设置状态",
|
||||
"Set": "已设置",
|
||||
|
||||
@@ -38,10 +38,14 @@ const mutations = {
|
||||
}
|
||||
},
|
||||
|
||||
updateChaMessageContentById(state, { id, content }) {
|
||||
updateChaMessageContentById(state, { id, data }) {
|
||||
const chats = state.activeChat.chats || []
|
||||
const filterChat = chats.filter((chat) => chat.message.id === id)?.[0] || {}
|
||||
filterChat.message.content = content
|
||||
if (Object.keys(filterChat).length > 0) {
|
||||
filterChat.message.content = data.message.content
|
||||
} else {
|
||||
chats?.push(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,17 @@ function reject(msg) {
|
||||
return new Promise((resolve, reject) => reject(msg))
|
||||
}
|
||||
|
||||
function isRenewalExpired(renewalTime) {
|
||||
const currentTimeStamp = Math.floor(new Date().getTime() / 1000)
|
||||
const sessionExpireTimestamp = VueCookie.get('jms_session_expire_timestamp')
|
||||
|
||||
if (!sessionExpireTimestamp) {
|
||||
return false
|
||||
}
|
||||
const timeDifferenceInSeconds = currentTimeStamp - parseInt(sessionExpireTimestamp, 10)
|
||||
return timeDifferenceInSeconds > renewalTime
|
||||
}
|
||||
|
||||
async function checkLogin({ to, from, next }) {
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
next()
|
||||
@@ -28,12 +39,16 @@ async function checkLogin({ to, from, next }) {
|
||||
return reject('No session mark found in cookie')
|
||||
} else if (sessionExpire === 'close') {
|
||||
let startTime = new Date().getTime()
|
||||
setInterval(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
const endTime = new Date().getTime()
|
||||
const delta = (endTime - startTime)
|
||||
startTime = endTime
|
||||
Vue.$log.debug('Set session expire: ', delta)
|
||||
VueCookie.set('jms_session_expire', 'close', { expires: '2m' })
|
||||
if (!isRenewalExpired(120)) {
|
||||
VueCookie.set('jms_session_expire', 'close', { expires: '2m' })
|
||||
} else {
|
||||
clearInterval(intervalId)
|
||||
}
|
||||
}, 10 * 1000)
|
||||
} else if (sessionExpire === 'age') {
|
||||
Vue.$log.debug('Session expire on age')
|
||||
@@ -156,7 +171,9 @@ export async function changeCurrentViewIfNeed({ to, from, next }) {
|
||||
|
||||
export async function startup({ to, from, next }) {
|
||||
// if (store.getters.inited) { return true }
|
||||
if (store.getters.inited) { return true }
|
||||
if (store.getters.inited) {
|
||||
return true
|
||||
}
|
||||
await store.dispatch('app/init')
|
||||
|
||||
// set page title
|
||||
|
||||
@@ -146,7 +146,7 @@ export default {
|
||||
},
|
||||
{
|
||||
name: 'BulkSyncDelete',
|
||||
title: this.$t('common.BulkSyncDelete'),
|
||||
title: this.$t('accounts.BulkSyncDelete'),
|
||||
type: 'primary',
|
||||
icon: 'fa fa-exchange',
|
||||
can: ({ selectedRows }) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="18">
|
||||
<el-row :gutter="24">
|
||||
<el-col :md="24" :sm="24">
|
||||
<BaseList :asset-id="object.id" :is-page="false" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="18">
|
||||
<el-row :gutter="24">
|
||||
<el-col :md="24" :sm="24">
|
||||
<BaseList :url="url" :columns-show="columnsShow" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -117,6 +117,7 @@ export default {
|
||||
name: 'GatewayCreate',
|
||||
query: {
|
||||
domain: this.object.id,
|
||||
platform_type: row.type.value,
|
||||
clone_from: row.id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,20 @@ export const assetFieldsMeta = (vm) => {
|
||||
clearable: true
|
||||
}
|
||||
},
|
||||
labels: {
|
||||
name: 'labels',
|
||||
label: vm.$t('assets.Label'),
|
||||
type: 'm2m',
|
||||
el: {
|
||||
multiple: true,
|
||||
url: '/api/v1/labels/labels/',
|
||||
ajax: {
|
||||
transformOption: (item) => {
|
||||
return { label: `${item.name}:${item.value}`, value: `${item.name}:${item.value}` }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
is_active: {
|
||||
type: 'switch'
|
||||
},
|
||||
|
||||
@@ -82,16 +82,18 @@
|
||||
</el-card>
|
||||
</div>
|
||||
<b>{{ $tc('ops.output') }}:</b>
|
||||
<span v-if="executionInfo.status" style="float: right">
|
||||
<span v-if="executionInfo.status && summary" style="float: right">
|
||||
<span>
|
||||
<span><b>{{ $tc('common.Status') }}: </b></span>
|
||||
<span
|
||||
:class="{
|
||||
'status_success':executionInfo.status==='success',
|
||||
'status_warning':executionInfo.status==='timeout',
|
||||
'status_danger':executionInfo.status==='failed'
|
||||
}"
|
||||
>{{ $tc('ops.' + executionInfo.status) }}</span>
|
||||
v-if="executionInfo.status==='timeout'"
|
||||
class="status_warning"
|
||||
>{{ $tc('ops.timeout') }}</span>
|
||||
<span v-else>
|
||||
<span class="status_success">{{ $tc('ops.success') + ': ' + summary.success }}</span>
|
||||
<span class="status_warning">{{ $tc('ops.Skip') + ': ' + summary.skip }}</span>
|
||||
<span class="status_danger">{{ $tc('ops.failed') + ': ' + summary.failed }}</span>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
<span><b>{{ $tc('ops.timeDelta') }}: </b></span>
|
||||
@@ -210,7 +212,12 @@ export default {
|
||||
ShowProgress: false,
|
||||
upload_interval: null,
|
||||
uploadFileList: [],
|
||||
SizeLimitMb: store.getters.publicSettings['FILE_UPLOAD_SIZE_LIMIT_MB']
|
||||
SizeLimitMb: store.getters.publicSettings['FILE_UPLOAD_SIZE_LIMIT_MB'],
|
||||
summary: {
|
||||
'success': 0,
|
||||
'failed': 0,
|
||||
'skip': 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -273,9 +280,21 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
taskStatusStat(summary) {
|
||||
const { ok, failures, dark, excludes, skipped } = summary
|
||||
|
||||
const failedKeys = Object.keys(failures)
|
||||
const darkKeys = Object.keys(dark)
|
||||
const excludesKeys = Object.keys(excludes)
|
||||
|
||||
this.summary['success'] = ok.length
|
||||
this.summary['failed'] = failedKeys.length + darkKeys.length
|
||||
this.summary['skip'] = excludesKeys.length + skipped.length
|
||||
},
|
||||
getTaskStatus() {
|
||||
getTaskDetail(this.currentTaskId).then(data => {
|
||||
this.executionInfo.status = data['status']
|
||||
this.taskStatusStat(data['summary'])
|
||||
if (this.executionInfo.status === 'success') {
|
||||
this.$message.success(this.$tc('ops.runSucceed'))
|
||||
clearInterval(this.upload_interval)
|
||||
@@ -334,11 +353,11 @@ export default {
|
||||
const filenameList = fileList.map((file) => file.name)
|
||||
const filenameCount = _.countBy(filenameList)
|
||||
for (const file of fileList) {
|
||||
file.is_same = filenameCount[file.name] > 1
|
||||
file.isSame = filenameCount[file.name] > 1
|
||||
}
|
||||
},
|
||||
sameFileStyle(file) {
|
||||
if (file.is_same) {
|
||||
if (file.isSame) {
|
||||
return { backgroundColor: 'var(--color-danger)' }
|
||||
}
|
||||
return ''
|
||||
@@ -362,7 +381,7 @@ export default {
|
||||
execute() {
|
||||
const { hosts, nodes } = this.getSelectedNodesAndHosts()
|
||||
for (const file of this.uploadFileList) {
|
||||
if (file.is_same) {
|
||||
if (file.isSame) {
|
||||
this.$message.error(this.$tc('ops.DuplicateFileExists'))
|
||||
return
|
||||
}
|
||||
@@ -476,7 +495,7 @@ export default {
|
||||
}
|
||||
|
||||
.status_success {
|
||||
color: var(--color-success);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.status_warning {
|
||||
|
||||
@@ -80,8 +80,7 @@ export default {
|
||||
timeCost: 0,
|
||||
cancel: 0
|
||||
},
|
||||
xtermConfig: {
|
||||
},
|
||||
xtermConfig: {},
|
||||
showHelpDialog: false,
|
||||
showOpenAdhocDialog: false,
|
||||
showOpenAdhocSaveDialog: false,
|
||||
@@ -484,7 +483,7 @@ export default {
|
||||
}
|
||||
|
||||
.status_success {
|
||||
color: var(--color-success);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.status_warning {
|
||||
|
||||
@@ -90,7 +90,7 @@ export default {
|
||||
form,
|
||||
{
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
timeout: 10 * 60 * 1000,
|
||||
timeout: 60 * 60 * 1000,
|
||||
disableFlashErrorMsg: true,
|
||||
params: { update: true }
|
||||
}
|
||||
|
||||
@@ -39,14 +39,14 @@ export default {
|
||||
title: this.$t('terminal.VirtualApp'),
|
||||
name: 'VirtualApp',
|
||||
hidden: () => {
|
||||
return !store.getters.publicSettings['VIRTUAL_APP_ENABLED']
|
||||
return !store.getters.publicSettings['VIRTUAL_APP_ENABLED'] || !this.$store.getters.hasValidLicense
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('terminal.AppProvider'),
|
||||
name: 'AppProvider',
|
||||
hidden: () => {
|
||||
return !store.getters.publicSettings['VIRTUAL_APP_ENABLED']
|
||||
return !store.getters.publicSettings['VIRTUAL_APP_ENABLED'] || !this.$store.getters.hasValidLicense
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -51,6 +51,22 @@ export default {
|
||||
]
|
||||
]
|
||||
],
|
||||
fieldsMeta: {
|
||||
GPT_BASE_URL: {
|
||||
el: {
|
||||
autocomplete: 'new-password'
|
||||
},
|
||||
helpText: this.$t('setting.Example', { example: 'https://api.openai.com/v1' })
|
||||
},
|
||||
GPT_API_KEY: {
|
||||
el: {
|
||||
autocomplete: 'new-password'
|
||||
}
|
||||
},
|
||||
GPT_PROXY: {
|
||||
helpText: this.$t('setting.Example', { example: 'http://ip:port' })
|
||||
}
|
||||
},
|
||||
submitMethod() {
|
||||
return 'patch'
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export default {
|
||||
this.$t('terminal.DatabasePort'),
|
||||
[
|
||||
'mysql_port', 'mariadb_port', 'postgresql_port',
|
||||
'redis_port', 'oracle_port_range'
|
||||
'redis_port', 'sqlserver_port', 'oracle_port_range'
|
||||
]
|
||||
],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
'name', 'host', 'actions',
|
||||
'http_port', 'https_port', 'ssh_port', 'rdp_port',
|
||||
'mysql_port', 'mariadb_port', 'postgresql_port',
|
||||
'redis_port', 'oracle_port_range'
|
||||
'redis_port', 'sqlserver_port', 'oracle_port_range'
|
||||
]
|
||||
},
|
||||
columnsMeta: {
|
||||
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
},
|
||||
callbacks: Object.freeze({
|
||||
click: () => {
|
||||
const msg = `${this.$t('users.AddAllMembersWarningMsg')} ?`
|
||||
const msg = this.$t('users.AddAllMembersWarningMsg')
|
||||
this.$confirm(msg, this.$tc('common.Info'), {
|
||||
type: 'warning',
|
||||
confirmButtonClass: 'el-button--danger',
|
||||
@@ -60,7 +60,8 @@ export default {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
}).catch(() => {})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -85,6 +86,9 @@ export default {
|
||||
width: 150,
|
||||
objects: this.object.users,
|
||||
formatter: DeleteActionFormatter,
|
||||
formatterArgs: {
|
||||
disabled: !this.$hasPerm('users.change_usergroup')
|
||||
},
|
||||
onDelete: function(col, row, cellValue, reload) {
|
||||
this.$axios.delete(
|
||||
'/api/v1/users/users-groups-relations/', {
|
||||
@@ -133,6 +137,7 @@ export default {
|
||||
},
|
||||
showHasObjects: false,
|
||||
hasObjectsId: this.object.users,
|
||||
disabled: !this.$hasPerm('users.change_usergroup'),
|
||||
performAdd: (items) => {
|
||||
const relationUrl = `/api/v1/users/users-groups-relations/`
|
||||
const groupId = this.object.id
|
||||
|
||||
@@ -28,6 +28,9 @@ export default {
|
||||
width: '160px',
|
||||
formatter: AmountFormatter,
|
||||
formatterArgs: {
|
||||
getItem(item) {
|
||||
return item.is_service_account ? null : item.name
|
||||
},
|
||||
routeQuery: {
|
||||
activeTab: 'GroupUser'
|
||||
}
|
||||
|
||||
@@ -174,6 +174,13 @@ export default {
|
||||
return 'post'
|
||||
}
|
||||
},
|
||||
afterGetFormValue(obj) {
|
||||
if (obj?.id) {
|
||||
obj.org_roles = obj.org_roles.map(({ id }) => id)
|
||||
obj.system_roles = obj.system_roles.map(({ id }) => id)
|
||||
}
|
||||
return obj
|
||||
},
|
||||
cleanFormValue(value) {
|
||||
const method = this.submitMethod()
|
||||
if (method === 'post' && value.password_strategy === 'email') {
|
||||
|
||||
Reference in New Issue
Block a user