Compare commits

..

67 Commits

Author SHA1 Message Date
fit2bot
b542bdce85 feat: Update v3.10.9 2024-04-23 19:39:32 +08:00
Bai
1a27b2489c perf: 优化 Web 资产详情时根据 autofill 类型返回对应的 spec_info 信息 2024-04-23 13:08:24 +08:00
Bryan
1b15a4d043 Merge pull request #3871 from jumpserver/dev
v3.10.9 (dev to master)
2024-04-22 19:44:33 +08:00
Bryan
7d3f818242 Merge pull request #3864 from jumpserver/v3.10
v3.10.8
2024-04-18 17:58:05 +08:00
Bryan
4e26f18d77 Merge pull request #3862 from jumpserver/dev
v3.10.8
2024-04-18 17:17:36 +08:00
Bryan
b22613617a Revert "build(deps): bump follow-redirects from 1.15.3 to 1.15.4"
This reverts commit e971cbf4a8.
2024-03-27 16:16:07 +08:00
dependabot[bot]
e971cbf4a8 build(deps): bump follow-redirects from 1.15.3 to 1.15.4
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-27 16:11:26 +08:00
wangruidong
4672abae35 fix: 刷新页面根据搜索条件过滤出对应的资源 2024-03-04 19:17:05 +08:00
Bryan
ba36d72602 Merge pull request #3761 from jumpserver/master
v3.10.4 (branch-v3.10)
2024-02-29 16:26:13 +08:00
Bryan
4bfbbba4c5 Merge pull request #3760 from jumpserver/dev
v3.10.4
2024-02-29 16:15:33 +08:00
Bryan
ea038ce43a Merge pull request #3697 from jumpserver/master
v3.10.2
2024-01-17 13:34:12 +00:00
Bryan
e16b19666c Merge pull request #3696 from jumpserver/dev
v3.10.2
2024-01-17 13:33:22 +00:00
Bryan
c7f5409eb6 Merge pull request #3694 from jumpserver/master
v3.10.2
2024-01-17 07:35:33 -04:00
Bryan
fdbd7d2222 Merge pull request #3693 from jumpserver/dev
v3.10.2
2024-01-17 07:24:50 -04:00
Bryan
ddbaeeafea Merge pull request #3668 from jumpserver/master
v3.10.1
2023-12-29 11:34:04 +05:00
Bryan
efb0e9dacb Merge pull request #3665 from jumpserver/dev
v3.10.1
2023-12-29 11:14:54 +05:00
huailei
f6f8301ad5 Revert "perf: 账号收集翻译"
This reverts commit 9a63ae63d4.
2023-12-22 15:25:31 +08:00
“huailei000”
9a63ae63d4 perf: 账号收集翻译 2023-12-22 11:31:45 +08:00
Bryan
1e007ccda3 Merge pull request #3642 from jumpserver/dev
v3.10
2023-12-21 15:15:52 +05:00
老广
d1d0b06b53 Merge pull request #3546 from jumpserver/dev
v3.9.0
2023-11-16 18:25:10 +08:00
Bryan
5fb70d2f24 Merge pull request #3450 from jumpserver/dev
v3.8.0
2023-10-19 03:33:53 -05:00
Bryan
b54a95430f Merge pull request #3404 from jumpserver/dev
v3.7.0
2023-09-21 17:04:42 +08:00
Bryan
4d8b4c45af Merge pull request #3355 from jumpserver/dev
v3.6.0
2023-08-17 14:00:33 +05:00
Bryan
a6d642df60 Merge pull request #3283 from jumpserver/dev
v3.5.0
2023-07-20 19:04:29 +08:00
Jiangjie.Bai
2e74f1522f Merge pull request #3222 from jumpserver/dev
v3.4.0
2023-06-15 14:51:36 +08:00
Jiangjie.Bai
fe615e0314 Merge pull request #3219 from jumpserver/dev
v3.4.0
2023-06-15 14:17:46 +08:00
Jiangjie.Bai
09f734e6fc Merge pull request #3135 from jumpserver/dev
v3.3.0
2023-05-18 19:18:11 +08:00
Jiangjie.Bai
3117046342 Merge pull request #3061 from jumpserver/dev
v3.2.0
2023-04-20 18:40:08 +08:00
Bai
b68aecb5cc fix: 批量更新资产平台help-text 2023-04-20 18:39:22 +08:00
Jiangjie.Bai
1c9b155d97 Merge pull request #3057 from jumpserver/dev
v3.2.0
2023-04-20 18:22:46 +08:00
Jiangjie.Bai
75b1be9864 Merge pull request #3019 from jumpserver/dev
v3.2.0 rc2
2023-04-14 19:01:37 +08:00
Jiangjie.Bai
615c3c1cf4 Merge pull request #3014 from jumpserver/dev
v3.2.0 rc1
2023-04-13 20:02:38 +08:00
Jiangjie.Bai
4d82231af4 Merge pull request #3012 from jumpserver/dev
v3.2.0 rc1
2023-04-13 19:22:38 +08:00
“huailei000”
c6cf6571b6 perf: ldap导入用户列表-组织下拉框设置最大宽度 2023-03-16 16:44:36 +08:00
Bai
8ea990d070 fix: 修复创建资产添加账号模版报错问题 2023-03-16 16:44:36 +08:00
“huailei000”
f4a32170d5 perf: message 2023-03-16 16:44:36 +08:00
ibuler
073508675e perf: 添加默认的信息 2023-03-16 16:44:36 +08:00
Jiangjie.Bai
1d6ca0a93a Merge pull request #2924 from jumpserver/dev
v3.1.0 rc4
2023-03-15 19:46:31 +08:00
Jiangjie.Bai
36aea652d6 Merge pull request #2788 from jumpserver/dev
v3.0.0
2023-02-23 20:16:41 +08:00
Jiangjie.Bai
1a42ce90ab Merge pull request #2760 from jumpserver/dev
v3.0.0-rc-latest
2023-02-22 22:21:54 +08:00
Jiangjie.Bai
31a401b55d Merge pull request #2463 from jumpserver/dev
v3.0.0-rc4
2023-01-31 18:55:34 +08:00
Jiangjie.Bai
582a84178d Merge pull request #2187 from jumpserver/dev
v2.28.0
2022-11-17 17:44:19 +08:00
Jiangjie.Bai
9b9f7c936c Merge pull request #2184 from jumpserver/dev
v2.28.0-rc5
2022-11-17 14:18:15 +08:00
Jiangjie.Bai
2a6100957f Merge pull request #2182 from jumpserver/dev
v2.28.0-rc4
2022-11-16 21:08:55 +08:00
Jiangjie.Bai
16606d6a27 Merge pull request #2176 from jumpserver/dev
v2.28.0-rc2
2022-11-14 10:01:05 +08:00
Jiangjie.Bai
0a612f50e6 Merge pull request #2164 from jumpserver/dev
v2.28.0-rc1
2022-11-10 17:45:47 +08:00
Jiangjie.Bai
fe36fa9390 Merge pull request #2117 from jumpserver/dev
v2.27.0-rc4
2022-10-18 21:02:10 +08:00
Jiangjie.Bai
ba109900ec Merge pull request #2113 from jumpserver/dev
v2.27.0-rc3
2022-10-18 11:20:57 +08:00
Jiangjie.Bai
ec7768267f Merge pull request #2105 from jumpserver/dev
v2.27.0-rc2
2022-10-14 11:01:32 +08:00
Jiangjie.Bai
cc58b374ab Merge pull request #2101 from jumpserver/dev
v2.27.0-rc1
2022-10-13 17:44:53 +08:00
Jiangjie.Bai
04ffbb8fd6 Merge pull request #2097 from jumpserver/dev
v2.27.0-rc1
2022-10-13 15:14:40 +08:00
Jiangjie.Bai
49880f6739 Merge pull request #2059 from jumpserver/dev
v2.26.0
2022-09-15 17:49:44 +08:00
Jiangjie.Bai
e6f98d58c4 Merge pull request #2057 from jumpserver/dev
v2.26.0-rc4
2022-09-15 16:18:03 +08:00
Jiangjie.Bai
fd1f16d43c Merge pull request #2050 from jumpserver/dev
v2.26.0-rc2
2022-09-13 17:41:39 +08:00
Jiangjie.Bai
968b2415b1 Merge pull request #2043 from jumpserver/dev
v2.26.0-rc1
2022-09-08 15:46:44 +08:00
Jiangjie.Bai
776090d6ba Merge pull request #2001 from jumpserver/dev
v2.25.0
2022-08-18 16:12:45 +08:00
Jiangjie.Bai
3a37952288 Merge pull request #1996 from jumpserver/dev
v2.25.0-rc4
2022-08-17 16:53:23 +08:00
Jiangjie.Bai
62b8fc0e3b Merge pull request #1994 from jumpserver/dev
v2.25.0-rc3
2022-08-16 19:08:23 +08:00
Jiangjie.Bai
b2028869cb Merge pull request #1986 from jumpserver/dev
v2.25.0-rc2
2022-08-12 18:06:56 +08:00
Jiangjie.Bai
5277a725f8 Merge pull request #1973 from jumpserver/dev
v2.25.0-rc1
2022-08-11 14:11:59 +08:00
Jiangjie.Bai
f137788c1a Merge pull request #1957 from jumpserver/dev
v2.24.0-rc5
2022-07-20 19:06:03 +08:00
Jiangjie.Bai
f7d17c8de7 Merge pull request #1954 from jumpserver/dev
v2.24.0-rc4
2022-07-19 16:18:13 +08:00
Jiangjie.Bai
feea70b0be Merge pull request #1944 from jumpserver/dev
v2.24.0-rc3
2022-07-18 12:05:42 +08:00
Jiangjie.Bai
04696ef3d6 Merge pull request #1940 from jumpserver/dev
v2.24.0-rc2
2022-07-15 18:07:37 +08:00
Jiangjie.Bai
1731f4f788 Merge pull request #1934 from jumpserver/dev
v2.24.0-rc1
2022-07-14 18:27:51 +08:00
Jiangjie.Bai
6f25d93909 Merge pull request #1931 from jumpserver/dev
v2.24.0-rc1
2022-07-14 17:51:58 +08:00
Jiangjie.Bai
46461ec324 Merge pull request #1925 from jumpserver/dev
v2.24.0-rc1
2022-07-14 15:12:15 +08:00
72 changed files with 2126 additions and 2457 deletions

View File

@@ -10,4 +10,3 @@ jobs:
- uses: jumpserver/action-generic-handler@master
env:
GITHUB_TOKEN: ${{ secrets.PRIVATE_TOKEN }}
I18N_TOKEN: ${{ secrets.I18N_TOKEN }}

1
GITSHA Normal file
View File

@@ -0,0 +1 @@
1a27b2489c119aa87da0ae95f5b4c2eadc6a0a2e

View File

@@ -34,7 +34,6 @@
"css-color-function": "^1.3.3",
"decimal.js": "^10.4.3",
"deepmerge": "^4.2.2",
"dompurify": "^3.1.6",
"echarts": "4.7.0",
"element-ui": "2.13.2",
"eslint-plugin-html": "^6.0.0",

View File

@@ -151,3 +151,6 @@ export default {
}
}
</script>
<style scoped>
</style>

View File

@@ -353,7 +353,7 @@ export default {
name: 'BulkVerify',
title: this.$t('accounts.BulkVerify'),
type: 'primary',
fa: 'fa-link',
fa: 'fa-handshake-o',
can: ({ selectedRows }) => {
return selectedRows.length > 0 &&
['clickhouse', 'redis', 'website', 'chatgpt'].indexOf(selectedRows[0].asset.type.value) === -1 &&

View File

@@ -83,10 +83,6 @@ export default {
type: String,
default: ''
},
type: {
type: String,
default: 'account'
},
title: {
type: String,
default: function() {
@@ -140,8 +136,7 @@ export default {
name: this.secretInfo.name,
secret: encryptPassword(this.modifiedSecret)
}
const url = this.type === 'account' ? `/api/v1/accounts/accounts` : `/api/v1/accounts/account-templates`
this.$axios.patch(`${url}/${this.account.id}/`, params).then(() => {
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, params).then(() => {
this.$message.success(this.$tc('common.updateSuccessMsg'))
})
},

View File

@@ -1,7 +1,6 @@
<template>
<Dialog
:close-on-click-modal="false"
:loading-status="!isLoaded"
:title="$tc('assets.Assets')"
custom-class="asset-select-dialog"
top="2vh"
@@ -22,7 +21,6 @@
:tree-setting="treeSetting"
class="tree-table"
v-bind="$attrs"
@loaded="handleTableLoaded"
/>
</Dialog>
</template>
@@ -65,7 +63,6 @@ export default {
data() {
const vm = this
return {
isLoaded: false,
dialogVisible: false,
rowSelected: _.cloneDeep(this.value) || [],
rowsAdd: [],
@@ -146,9 +143,6 @@ export default {
if (selectValueIndex > -1) {
this.rowSelected.splice(selectValueIndex, 1)
}
},
handleTableLoaded() {
this.isLoaded = true
}
}
}

View File

@@ -28,6 +28,7 @@
<script>
import Select2 from '@/components/Form/FormFields/Select2.vue'
import AssetSelectDialog from './dialog.vue'
import { b } from 'css-color-function/lib/adjusters'
export default {
componentName: 'AssetSelect',
@@ -80,6 +81,7 @@ export default {
}
},
methods: {
b,
handleFocus() {
this.$refs.select2.selectRef.blur()
this.dialogVisible = true

View File

@@ -31,10 +31,6 @@ export default {
type: String,
default: '/api/v1/assets/assets/'
},
typeUrl: {
type: String,
default: '/api/v1/assets/nodes/category/tree/'
},
nodeUrl: {
type: String,
default: '/api/v1/assets/nodes/'
@@ -105,9 +101,9 @@ export default {
showAssets: false,
showSearch: false,
customTreeHeaderName: this.$t('assets.BuiltinTree'),
url: this.typeUrl,
url: '/api/v1/assets/nodes/category/tree/',
nodeUrl: this.treeSetting?.nodeUrl || this.nodeUrl,
treeUrl: `${this.typeUrl}?assets=${showAssets ? '1' : '0'}&count_resource=${this.treeSetting.countResource || 'asset'}`,
treeUrl: `/api/v1/assets/nodes/category/tree/?assets=${showAssets ? '1' : '0'}&count_resource=${this.treeSetting.countResource || 'asset'}`,
callback: {
onSelected: (event, treeNode) => this.getAssetsUrl(treeNode)
}

View File

@@ -82,7 +82,6 @@
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import { encryptPassword } from '@/utils/crypto'
export default {
name: 'UserConfirmDialog',
@@ -200,7 +199,7 @@ export default {
const data = {
confirm_type: this.confirmTypeRequired,
mfa_type: this.confirmTypeRequired === 'mfa' ? this.subTypeSelected : '',
secret_key: this.confirmTypeRequired === 'password' ? encryptPassword(this.secretValue) : this.secretValue
secret_key: this.secretValue
}
this.$axios.post(`/api/v1/authentication/confirm/`, data).then(res => {
this.callback()

View File

@@ -78,7 +78,7 @@ export default {
formatterData = data
}
return (
<span style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word', lineHeight: '1.2' }}>{formatterData}</span>
<span>{formatterData}</span>
)
}
if (this.value instanceof Array) {

View File

@@ -9,13 +9,11 @@
v-bind="$attrs"
v-on="$listeners"
>
<div v-loading="loadingStatus">
<slot />
</div>
<slot />
<div slot="footer" class="dialog-footer">
<slot name="footer">
<el-button v-if="showCancel && showButtons" @click="onCancel">{{ cancelTitle }}</el-button>
<el-button v-if="showConfirm && showButtons" :disabled="loadingStatus" type="primary" @click="onConfirm">
<el-button v-if="showConfirm && showButtons" :loading="loadingStatus" type="primary" @click="onConfirm">
{{ confirmTitle }}
</el-button>
</slot>
@@ -73,16 +71,13 @@ export default {
}
},
data() {
return {
}
return {}
},
computed: {
iWidth() {
return this.$store.getters.isMobile ? '1000px' : this.width
}
},
mounted() {
},
methods: {
onCancel() {
this.$emit('cancel')

View File

@@ -7,6 +7,7 @@ import BasicTree from '@/components/Form/FormFields/BasicTree.vue'
import JsonEditor from '@/components/Form/FormFields/JsonEditor.vue'
import { assignIfNot } from '@/utils/common'
import TagInput from '@/components/Form/FormFields/TagInput.vue'
import TransferSelect from '@/components/Form/FormFields/TransferSelect.vue'
export class FormFieldGenerator {
constructor(emit) {
@@ -133,6 +134,9 @@ export class FormFieldGenerator {
case 'comment':
field.el.type = 'textarea'
break
case 'users':
field.component = TransferSelect
field.el.label = field.label
}
return field
}

View File

@@ -7,11 +7,18 @@
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="2">
{{ this.$t('common.CronTab.from') }}
<el-input-number v-model="cycle01" :max="60" :min="0" size="mini" /> -
<el-input-number v-model="cycle02" :max="60" :min="0" size="mini" /> {{ this.$t('common.CronTab.min') }}
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="3">
{{ this.$t('common.CronTab.from') }}
<el-input-number v-model="average02" :max="60" :min="1" size="mini" />
{{ this.$t('common.CronTab.min') }}{{ this.$t('common.CronTab.executeOnce') }}
<el-input-number v-model="average02" :max="60" :min="1" size="mini" /> {{ this.$t('common.CronTab.min') }}{{ this.$t('common.CronTab.executeOnce') }}
</el-radio>
</el-form-item>
@@ -26,7 +33,7 @@
size="small"
style="width:100%"
>
<el-option v-for="item in 60" :key="item" :value="item-1">{{ item - 1 }}</el-option>
<el-option v-for="item in 60" :key="item" :value="item-1">{{ item-1 }}</el-option>
</el-select>
</el-radio>
</el-form-item>
@@ -151,7 +158,7 @@ export default {
</script>
<style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
</style>

View File

@@ -85,7 +85,12 @@ export default {
}
},
public: {
disabled: this.protocol.name === 'winrm'
disabled: this.protocol.name === 'winrm',
hidden: (formValue) => {
if (this.protocol.name === 'winrm') {
formValue['public'] = false
}
}
}
}
}

View File

@@ -225,6 +225,9 @@ export default {
handler(newValue, oldValue) {
},
deep: true
},
iOptions(val) {
this.remote = val.length !== 0
}
},
async mounted() {

View File

@@ -11,7 +11,6 @@
/>
<Dialog
v-if="showTransfer"
:loading-status="!isLoaded"
:close-on-click-modal="false"
:title="label"
:visible.sync="showTransfer"
@@ -19,7 +18,6 @@
width="730px"
@cancel="handleTransCancel"
@confirm="handleTransConfirm"
v-on="$listeners"
>
<krryPaging v-if="selectInitialized" ref="pageTransfer" class="transfer" v-bind="pagingTransfer" />
</Dialog>
@@ -79,16 +77,13 @@ export default {
if (keyword) {
params['search'] = keyword
}
this.isLoaded = false
const data = await this.$axios.get(url, { params })
this.isLoaded = true
return data['results'].map(item => {
const n = transformOption(item)
return { id: n.value, label: n.label }
})
}
return {
isLoaded: false,
showTransfer: false,
selectInitialized: false,
select2: {
@@ -171,3 +166,7 @@ export default {
}
}
</script>
<style scoped>
</style>

View File

@@ -42,7 +42,7 @@ export default {
patterns.push([/\d/, i18n.t('common.password.NUMBER_REQUIRED')])
}
if (passwordRule['SECURITY_PASSWORD_SPECIAL_CHAR']) {
const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~@#¥……&*()——|{}【】‘;:”“'。,、?_+-]")
const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~@#¥……&*()——|{}【】‘;:”“'。,、?]")
patterns.push([pattern, i18n.t('common.password.SPECIAL_CHAR_REQUIRED')])
}
for (const [pattern, msg] of patterns) {

View File

@@ -53,34 +53,27 @@ export default {
},
props: {
boxTitle: {
type: Array,
default: () => []
type: Array
},
boxOperation: {
type: Array,
default: () => []
type: Array
},
// 地域数据
dataObj: {
type: Object,
default: () => {}
type: Object
},
// 已选数据
selectedData: {
type: Array,
default: () => []
type: Array
},
onChangeSelected: {
type: Function,
default: () => () => {}
type: Function
},
filterable: {
type: Boolean,
default: () => false
type: Boolean
},
filterPlaceholder: {
type: String,
default: () => ''
type: String
}
},
data() {

View File

@@ -46,7 +46,7 @@
<div class="vip-footer">
<el-button
type="text"
:disabled="selectedDistrict.length<=0"
:disabled="selectedDistrict.length > 0 ? false : true"
size="small"
round
@click="checkedSelected"
@@ -62,29 +62,23 @@ export default {
components: {},
props: {
title: {
type: String,
default: () => ''
type: String
},
operation: {
type: String,
default: () => ''
type: String
},
operateId: {
type: Number,
default: () => 0
type: Number
},
// 区域数据
districtList: {
type: Array,
default: () => []
type: Array
},
filterable: {
type: Boolean,
default: () => false
type: Boolean
},
filterPlaceholder: {
type: String,
default: () => ''
type: String
}
},
data() {

View File

@@ -69,48 +69,12 @@ class StrategyPersistSelection extends StrategyAbstract {
* 用户切换当前页的多选
*/
onSelectAll(selection, selectable = () => true) {
const { id, selected, data } = this.elDataTable
const selectableRows = data.filter(selectable)
// const isSelected = !!selection.length
// 创建已选择项的 id 集合,用于快速查找
const selectedIds = new Set(selected.map(r => r[id]))
const currentPageIds = new Set(selectableRows.map(row => row[id]))
// 前页面的选中状态
const currentPageSelectedCount = selectableRows.filter(row =>
selectedIds.has(row[id])
).length
// 判断是全选还是取消全选
const shouldSelectAll = currentPageSelectedCount < selectableRows.length
this.elTable.clearSelection()
if (shouldSelectAll) {
selectableRows.forEach(row => {
if (!selectedIds.has(row[id])) selected.push(row)
this.elTable.toggleRowSelection(row, true)
// ! 这里需要触发事件,否则在 el-table 中无法触发 selection-change 事件
this.elDataTable.$emit('toggle-row-selection', true, row)
})
} else {
const newSelected = []
selected.forEach(row => {
if (!currentPageIds.has(row[id])) {
newSelected.push(row)
} else {
this.elDataTable.$emit('toggle-row-selection', false, row)
}
})
this.elDataTable.selected = newSelected
}
this.elDataTable.$emit('selection-change', this.elDataTable.selected)
const isSelected = !!selection.length
this.elDataTable.data.forEach(r => {
if (selectable(r)) {
this.toggleRowSelection(r, isSelected)
}
})
}
/**
* toggleRowSelection和clearSelection管理elDataTable的selected数组
@@ -119,17 +83,14 @@ class StrategyPersistSelection extends StrategyAbstract {
toggleRowSelection(row, isSelected) {
const { id, selected } = this.elDataTable
const foundIndex = selected.findIndex(r => r[id] === row[id])
if (typeof isSelected === 'undefined') {
isSelected = foundIndex <= -1
}
if (isSelected && foundIndex === -1) {
selected.push(row)
} else if (!isSelected && foundIndex > -1) {
selected.splice(foundIndex, 1)
}
this.elDataTable.$emit('toggle-row-selection', isSelected, row)
this.updateElTableSelection()
}
@@ -142,17 +103,14 @@ class StrategyPersistSelection extends StrategyAbstract {
*/
updateElTableSelection() {
const { data, id, selected } = this.elDataTable
const selectedIds = new Set(selected.map(r => r[id]))
this.elTable.clearSelection()
data.forEach(row => {
const shouldBeSelected = selectedIds.has(row[id])
if (!this.elTable) return
if (shouldBeSelected) {
this.elTable.toggleRowSelection(row, true)
// 历史勾选的行已经不在当前页了所以要将当前页的行数据和selected合并
const mergeData = _.uniqWith([...data, ...selected], _.isEqual)
mergeData.forEach(r => {
const isSelected = !!selected.find(r2 => r[id] === r2[id])
if (!this.elTable) {
return
}
this.elTable.toggleRowSelection(r, isSelected)
})
}
}

View File

@@ -153,8 +153,6 @@ export default {
this.toggleRowSelection(row, true)
}
}
this.$emit('loaded')
},
handleSizeChange(val) {
localStorage.setItem('paginationSize', val)

View File

@@ -48,7 +48,6 @@
import Dialog from '@/components/Dialog/index.vue'
import { createSourceIdCache } from '@/api/common'
import * as queryUtil from '@/components/Table/DataTable/compenents/el-data-table/utils/query'
import { download } from '@/utils/common'
export default {
name: 'ExportDialog',
@@ -188,7 +187,10 @@ export default {
})
},
downloadCsv(url) {
download(url)
const a = document.createElement('a')
a.href = url
a.click()
window.URL.revokeObjectURL(url)
},
async defaultPerformExport(selectRows, exportOption, q, exportTypeOption) {
const url = (process.env.VUE_APP_ENV === 'production') ? (`${this.url}`) : (`${process.env.VUE_APP_BASE_API}${this.url}`)

View File

@@ -68,7 +68,7 @@
<script>
import Dialog from '@/components/Dialog/index.vue'
import ImportTable from '@/components/Table/ListTable/TableAction/ImportTable.vue'
import { download, getErrorResponseMsg } from '@/utils/common'
import { getErrorResponseMsg } from '@/utils/common'
import { createSourceIdCache } from '@/api/common'
export default {
@@ -221,7 +221,10 @@ export default {
this.$message.success(msg)
},
downloadCsv(url) {
download(url)
const a = document.createElement('a')
a.href = url
a.click()
window.URL.revokeObjectURL(url)
},
async handleImportConfirm() {
await this.$refs['importTable'].performUpload()

View File

@@ -1,6 +1,6 @@
<template>
<div>
<el-row type="flex" align="center">
<el-row>
<el-col :md="8" :sm="24">
<div class="tableFilter">
<el-radio-group v-model="importStatusFilter" size="small">
@@ -11,7 +11,7 @@
</el-radio-group>
</div>
</el-col>
<el-col :md="16" :sm="24" style="text-align: center; display: flex; align-items: center">
<el-col :md="8" :sm="24" style="text-align: center">
<span class="summary-item summary-total"> {{ $t('common.Total') }}: {{ totalCount }}</span>
<span class="summary-item summary-success"> {{ $t('common.Success') }}: {{ successCount }}</span>
<span class="summary-item summary-failed"> {{ $t('common.Failed') }}: {{ failedCount }}</span>

View File

@@ -122,9 +122,6 @@ export default {
return this.hasLeftActions ? 'right' : 'left'
}
},
created() {
this.$emit('done')
},
methods: {
handleTagSearch(val) {
this.searchTable(val)
@@ -147,121 +144,119 @@ export default {
</script>
<style lang='scss' scoped>
.table-header {
/*display: flex;*/
/*flex-direction: row;*/
/*justify-content: space-between;*/
}
.table-header {
/*display: flex;*/
/*flex-direction: row;*/
/*justify-content: space-between;*/
}
.right-side-item {
}
.right-side-item {
}
.right-side-actions > > > .el-button {
border: none;
padding: 5px;
font-size: 14px;
width: 26px;
height: 26px;
color: #888;
background-color: transparent;
}
.right-side-actions >>> .el-button {
border: none;
padding: 5px;
font-size: 14px;
width: 26px;
height: 26px;
color: #888;
background-color: transparent;
}
.right-side-actions > > > .fa {
height: 16px;
width: 16px;
}
.right-side-actions >>> .fa {
height: 16px;
width: 16px;
}
.right-side-actions > > > .el-button:hover {
background-color: rgb(0, 0, 0, 0.05);
}
.right-side-actions >>> .el-button:hover {
background-color: rgb(0, 0, 0, 0.05);
}
.action-search > > > .el-input__suffix i {
font-weight: 500;
color: #888;
}
.action-search >>> .el-input__suffix i {
font-weight: 500;
color: #888;
}
.action-search > > > .el-cascader {
line-height: 32px !important;
}
.action-search >>> .el-cascader {
line-height: 32px !important;
}
.right-side-actions {
display: flex;
padding-left: 10px;
align-items: center;
justify-content: center;
}
.right-side-actions {
display: flex;
padding-left: 10px;
align-items: center;
justify-content: center;
}
.table-action-right-side {
display: flex;
justify-content: center;
}
.table-action-right-side {
display: flex;
justify-content: center;
}
.export-item {
display: block;
padding: 5px 20px;
}
.export-item {
display: block;
padding: 5px 20px;
}
.datepicker {
margin-left: 10px;
}
.datepicker {
margin-left: 10px;
}
.table-header {
line-height: 32px;
}
.table-header {
line-height: 32px;
}
.left-side {
float: left;
display: block;
& > > > .action-item.el-dropdown {
height: 33px;
& > .el-button {
height: 100%;
.left-side {
float: left;
display: block;
&>>> .action-item.el-dropdown {
height: 33px;
&> .el-button {
height: 100%;
}
}
}
}
.right-side {
float: right;
}
.right-side {
float: right;
}
.search {
display: flex;
flex-direction: row;
}
.search {
display: flex;
flex-direction: row;
}
.mobile .search {
display: inherit;
}
.mobile .search {
display: inherit;
}
.mobile .search .datepicker {
margin-left: 0;
}
.mobile .search .datepicker {
margin-left: 0;
}
.search.left {
float: left;
padding: 0 !important;
}
.search.left {
float: left;
padding: 0 !important;
}
.search.right {
float: right;
}
.search.right {
float: right;
}
.mobile .search.right {
float: none;
}
.mobile .search.right {
float: none;
}
.mobile .search.right .action-search {
width: 100%;
}
.mobile .search.right .action-search {
width: 100%;
}
.mobile .right-side {
padding-top: 5px;
}
.mobile .right-side {
padding-top: 5px;
}
.filter-field.right-side-item.action-search {
height: 34px;
}
.filter-field.right-side-item.action-search {
height: 34px;
}
</style>

View File

@@ -8,11 +8,9 @@
:selected-rows="selectedRows"
:table-url="tableUrl"
v-bind="iHeaderActions"
@done="handleActionInitialDone"
/>
<IBox class="table-content">
<AutoDataTable
v-if="actionInit"
ref="dataTable"
:config="iTableConfig"
:filter-table="filter"
@@ -75,10 +73,7 @@ export default {
return {
selectedRows: [],
init: false,
isDeactivated: false,
extraQuery: extraQuery,
actionInit: this.headerActions.has === false,
initQuery: {}
extraQuery: extraQuery
}
},
computed: {
@@ -171,36 +166,14 @@ export default {
}
},
methods: {
handleActionInitialDone() {
setTimeout(() => {
this.actionInit = true
}, 100)
},
handleSelectionChange(val) {
this.selectedRows = val
},
reloadTable() {
this.dataTable.getList()
},
updateInitQuery(attrs) {
if (!this.actionInit) {
this.initQuery = attrs
for (const key in attrs) {
this.$set(this.extraQuery, key, attrs[key])
}
return true
}
const removeKeys = Object.keys(this.initQuery).filter(key => !attrs[key])
for (const key of removeKeys) {
this.$delete(this.extraQuery, key)
}
},
search(attrs) {
this.$log.debug('ListTable: search table', attrs)
const init = this.updateInitQuery(attrs)
if (init) {
return
}
this.$emit('TagSearch', attrs)
this.$refs.dataTable?.$refs.dataTable?.search(attrs, true)
},

View File

@@ -1,5 +1,5 @@
<template>
<span class="date">{{ dateValue }}</span>
<span>{{ value }}</span>
</template>
<script>
@@ -10,31 +10,24 @@ export default {
name: 'DateFormatter',
extends: BaseFormatter,
data() {
// let value
// if (this.cellValue) {
// value = toSafeLocalDateStr(this.cellValue)
// } else {
// value = '-'
// }
let value
if (this.cellValue) {
value = toSafeLocalDateStr(this.cellValue)
} else {
value = '-'
}
// const locale = this.$i18n.locale
// const value = dt.toLocaleString(locale, { hourCycle: 'h23' })
// debug(this.$i18n.locale)
// return {
// value: value
// }
return {
value: value
}
// return {
// value: `${year}-${month}-${date} ${hour}:${minutes}:${seconds}`
// }
return {}
},
computed: {
dateValue() {
if (this.cellValue) {
return toSafeLocalDateStr(this.cellValue)
} else {
return '-'
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -64,7 +64,7 @@ export default {
}
return text
}
return this.items?.distribution || '-'
return '-'
}
}
}

View File

@@ -27,7 +27,7 @@
</a>
<a
v-if="formatterArgs.showEditBtn"
:class="[{ 'disabled-link': this.$store.getters.currentOrgIsRoot },'edit-btn']"
class="edit-btn"
style="padding-left: 5px"
@click="showDialog = true"
>
@@ -269,11 +269,4 @@ export default {
.tag-tip {
margin-top: 10px;
}
.disabled-link {
pointer-events: none;
color: grey;
cursor: default;
text-decoration: none;
}
</style>

View File

@@ -213,10 +213,12 @@ export default {
delete routeFilter.search
}
const asFilterTags = _.cloneDeep(this.filterTags)
this.filterTags = {
...asFilterTags,
...routeFilter
}
setTimeout(() => {
this.filterTags = {
...asFilterTags,
...routeFilter
}
}, 100)
},
getValueLabel(key, value) {
for (const field of this.options) {

View File

@@ -39,7 +39,7 @@ export default {
showRenameBtn: false,
drag: {
isCopy: false,
isMove: true
isMove: false
}
},
callback: {

View File

@@ -18,15 +18,14 @@
/>
</el-col>
<el-col v-show="isShow" :span="span">
<VueMarkdown class="result-html" :source="sanitizedValue" :html="false" :show="true" />
<VueMarkdown class="result-html" :source="iValue" :show="true" :html="false" />
</el-col>
</el-row>
<VueMarkdown v-else class="source" :html="false" :source="sanitizedValue" />
<VueMarkdown v-else class="source" :source="iValue" :html="false" />
</div>
</template>
<script>
import DOMPurify from 'dompurify'
import VueMarkdown from 'vue-markdown'
import 'github-markdown-css/github-markdown-light.css'
@@ -57,17 +56,6 @@ export default {
iValue: this.value
}
},
computed: {
sanitizedValue() {
// 转义特殊字符
let content = this.iValue.replace(/\\/g, '\\\\').replace(/\$/g, '\\$')
// 使用 DOMPurify 进行 XSS 过滤
content = DOMPurify.sanitize(content)
return content
}
},
mounted() {
this.$nextTick(() => {
this.resizeObserver = new ResizeObserver(entries => {

View File

@@ -48,7 +48,6 @@ export default {
fontFamily: 'monaco, Consolas, "Lucida Console", monospace',
lineHeight: 1.2,
fontSize: 13,
scrollback: 9999999,
rightClickSelectsWord: true,
theme: {
background: '#fff',
@@ -84,7 +83,7 @@ export default {
callback: () => {
this.xterm.selectAll()
const text = this.xterm.getSelection()
const filename = `${this.$route.query?.type}_${this.$route.query?.taskId}.log`
const filename = `shortcut_cmd_${this.$route.query?.taskId}.log`
downloadText(text, filename)
}
}

View File

@@ -721,7 +721,6 @@
"BatchActivate": "Batch activate",
"SyncSelected": "Sync selected",
"bulkDeploy": "Bulk deploy",
"BulkVerify": "Bulk verify",
"bulkDeleteErrorMsg": "Bulk delete failed: ",
"bulkDeleteSuccessMsg": "Bulk delete success",
"bulkRemoveErrorMsg": "Bulk remove failed: ",
@@ -1931,7 +1930,6 @@
"CheckViewAcceptor": "View more acceptor",
"Assignees": "Assignees",
"Close": "Close",
"CancelTicket": "Cancel Ticket",
"OpenStatus": "Open",
"CloseStatus": "Close",
"Comment": "Comment",
@@ -2137,8 +2135,7 @@
"passwordWillExpiredSuffixMsg": " days.Please change your password as soon as possible.",
"dateLastLogin": "Date last login",
"AddAllMembersWarningMsg": "Are you sure you want to add all members?",
"disallowSelfUpdateFields": "Not allowed to modify the current fields oneself",
"GlobalDisableMfaMsg": "Global enforcement has been enabled"
"disallowSelfUpdateFields": "Not allowed to modify the current fields oneself"
},
"notifications": {
"MessageType": "Message Type",
@@ -2274,8 +2271,6 @@
"HostnameStrategy": "Used to produce the asset hostname. For example, 1. Instance name (instanceDemo)2. Instance name and Partial IP (instanceDemo-250.1)",
"IsAlwaysUpdate": "Keep assets up to date",
"FullySynchronous": "Assets fully synchronized",
"ReleaseAssets": "Release assets",
"ReleaseAssetsHelpTips": "Whether to automatically delete assets synchronized through this task and released on the cloud at the end of the task",
"AccountCreate": "Create account",
"AccountList": "Account list",
"AccountUpdate": "Update account",

View File

@@ -717,7 +717,6 @@
"SyncSuccessMsg": "同期に成功しました",
"SyncSelected": "選択した同期",
"bulkDeploy": "一括デプロイ",
"BulkVerify": "一括テスト",
"bulkSyncErrorMsg": "一括同期に失敗しました:",
"bulkDeleteErrorMsg": "一括削除に失敗しました:",
"bulkDeleteSuccessMsg": "一括削除に成功しました",
@@ -1927,7 +1926,6 @@
"Assignee": "処理者",
"Assignees": "処理待ち",
"Close": "閉じる",
"CancelTicket": "作業指示をキャンセルする",
"OpenStatus": "オン",
"CloseStatus": "閉じる",
"Comment": "備考",
@@ -2126,8 +2124,7 @@
"passwordWillExpiredPrefixMsg": "パスワードはまもなく",
"passwordWillExpiredSuffixMsg": "期限が切れた後、できるだけ早くパスワードを変更してください。",
"AddAllMembersWarningMsg": "すべてのメンバーを追加してもよろしいですか?",
"disallowSelfUpdateFields": "現在のフィールドを自分で変更することは許可されていません",
"GlobalDisableMfaMsg": "グローバルでの強制が有効になっています"
"disallowSelfUpdateFields": "現在のフィールドを自分で変更することは許可されていません"
},
"notifications": {
"MessageType": "メッセージタイプ",
@@ -2270,8 +2267,6 @@
"HostnameStrategy": "資産を生成するためにホスト名。例: 1. インスタンス名 (instanceDemo) 2.インスタンス名と一部IP (下位2桁) (instanceDemo-250.1)",
"IsAlwaysUpdate": "資産は常に最新です",
"FullySynchronous": "資産完全にシンクロします",
"ReleaseAssets": "資産の同期解放",
"ReleaseAssetsHelpTips": "タスクの終了時に、このタスクを介して同期され、クラウド上で解放された資産を自動的に削除するかどうか",
"AccountCreate": "アカウントの作成",
"AccountList": "アカウントリスト",
"AccountUpdate": "アカウントの更新",
@@ -2430,4 +2425,4 @@
"BindResource": "リソースを関連付ける",
"SelectResource": "リソースを選択"
}
}
}

View File

@@ -771,7 +771,6 @@
"BatchActivate": "批量激活",
"SyncSelected": "同步所选",
"bulkDeploy": "批量部署",
"BulkVerify": "批量测试",
"bulkDeleteErrorMsg": "批量删除失败: ",
"bulkDeleteSuccessMsg": "批量删除成功",
"bulkRemoveErrorMsg": "批量移除失败: ",
@@ -1913,7 +1912,6 @@
"Assignee": "处理人",
"Assignees": "待处理人",
"Close": "关闭",
"CancelTicket": "取消工单",
"OpenStatus": "审批中",
"CloseStatus": "已完成",
"Comment": "备注",
@@ -2117,8 +2115,7 @@
"passwordExpired": "密码过期了",
"passwordWillExpiredPrefixMsg": "密码即将在 ",
"passwordWillExpiredSuffixMsg": "天 后过期,请尽快修改您的密码。",
"disallowSelfUpdateFields": "不允许自己修改当前字段",
"GlobalDisableMfaMsg": "全局已强制开启"
"disallowSelfUpdateFields": "不允许自己修改当前字段"
},
"notifications": {
"MessageType": "消息类型",
@@ -2189,8 +2186,6 @@
"HostnameStrategy": "用于生成资产主机名。例如1. 实例名称 (instanceDemo)2. 实例名称和部分IP(后两位) (instanceDemo-250.1)",
"IsAlwaysUpdate": "资产保持最新",
"FullySynchronous": "资产完全同步",
"ReleaseAssets": "同步释放资产",
"ReleaseAssetsHelpTips": "是否在任务结束时,自动删除通过此任务同步下来且已经在云上释放的资产",
"AccountCreate": "创建账户",
"AccountList": "云账号",
"AccountUpdate": "更新账户",

View File

@@ -771,7 +771,6 @@
"BatchActivate": "批次啟用",
"SyncSelected": "同步所選",
"bulkDeploy": "批次部署",
"BulkVerify": "批次測試",
"bulkDeleteErrorMsg": "批次刪除失敗: ",
"bulkDeleteSuccessMsg": "批次刪除成功",
"bulkRemoveErrorMsg": "批次移除失敗: ",
@@ -1913,7 +1912,6 @@
"Assignee": "處理人",
"Assignees": "待處理人",
"Close": "關閉",
"CancelTicket": "取消工單",
"OpenStatus": "審批中",
"CloseStatus": "已完成",
"Comment": "備註",

View File

@@ -81,7 +81,7 @@ export default {
},
{
label: this.$t('common.Version'),
value: 'version-dev'
value: 'v3.10.9'
},
{
label: this.$t('common.PermissionCompany'),

View File

@@ -61,6 +61,7 @@ export default {
break
case 'logout':
this.logout()
window.location.href = `${process.env.VUE_APP_LOGOUT_PATH}?next=${this.$route.fullPath}`
break
case 'apiKey':
this.$router.push('/profile/api-keys')
@@ -72,14 +73,7 @@ export default {
this.$router.push('/profile/user/setting')
}
},
async logout() {
const currentOrg = this.$store.getters.currentOrg
if (currentOrg.autoEnter || currentOrg.is_system) {
await this.$store.dispatch('users/setCurrentOrg', this.$store.getters.preOrg)
}
window.location.href = `${process.env.VUE_APP_LOGOUT_PATH}?next=${this.$route.fullPath}`
logout() {
}
}
}

View File

@@ -1,7 +1,5 @@
import { getProfile as apiGetProfile, logout } from '@/api/users'
import {
getCurrentOrgLocal, getPreOrgLocal, getTokenFromCookie, saveCurrentOrgLocal, setPreOrgLocal
} from '@/utils/auth'
import { getCurrentOrgLocal, getPreOrgLocal, getTokenFromCookie, saveCurrentOrgLocal, setPreOrgLocal } from '@/utils/auth'
import orgUtil from '@/utils/org'
import { resetRouter } from '@/router'
import Vue from 'vue'
@@ -71,12 +69,10 @@ const mutations = {
state.consoleOrgs = state.consoleOrgs.filter(i => i.id !== org.id)
},
SET_CURRENT_ORG(state, org) {
// 系统组织不设置成 Pre org
const currentOrg = state.currentOrg
if (currentOrg && !currentOrg.autoEnter && !currentOrg.is_system) {
state.preOrg = currentOrg
setPreOrgLocal(state.username, currentOrg)
// 系统组织和全局组织不设置成 Pre org
if (!state.currentOrg?.autoEnter) {
state.preOrg = state.currentOrg
setPreOrgLocal(state.username, state.currentOrg)
}
state.currentOrg = org
saveCurrentOrgLocal(state.username, org)
@@ -146,8 +142,7 @@ const actions = {
const systemOrg = {
id: orgUtil.SYSTEM_ORG_ID,
name: 'SystemSetting',
is_system: true,
autoEnter: new Date().getTime()
autoEnter: true
}
commit('SET_CURRENT_ORG', systemOrg)
},
@@ -162,8 +157,7 @@ const actions = {
const globalOrg = {
id: orgUtil.GLOBAL_ORG_ID,
name: 'Global',
is_root: true,
autoEnter: new Date().getTime()
autoEnter: true
}
commit('SET_CURRENT_ORG', globalOrg)
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -92,10 +92,6 @@
background: url('./icons/db2.png') no-repeat center left transparent;
}
&.dameng_ico_docu {
background: url('./icons/dameng.png') no-repeat center left transparent;
}
&.private_ico_docu {
background: url('./icons/private.png') no-repeat center left transparent;
}

View File

@@ -42,14 +42,8 @@ export function getCurrentOrgLocal(username) {
export function saveCurrentOrgLocal(username, org) {
const key = CURRENT_ORG_KEY + '_' + username
if (org) {
localStorage.setItem(key, JSON.stringify(org))
VueCookie.set('X-JMS-ORG', org.id)
} else {
localStorage.removeItem(key)
VueCookie.delete('X-JMS-ORG')
}
localStorage.setItem(key, JSON.stringify(org))
VueCookie.set('X-JMS-ORG', org.id)
}
export function setPreOrgLocal(username, org) {

View File

@@ -363,35 +363,13 @@ export function downloadText(content, filename) {
}
export function download(downloadUrl, filename) {
const iframe = document.createElement('iframe')
iframe.style.display = 'none'
document.body.appendChild(iframe)
const timeout = 1000 * 60 * 30
const a = document.createElement('a')
a.href = downloadUrl
if (filename) {
fetch(downloadUrl)
.then(response => response.blob())
.then(blob => {
const url = URL.createObjectURL(blob)
const a = iframe.contentWindow.document.createElement('a')
a.href = url
a.download = filename
iframe.contentWindow.document.body.appendChild(a)
a.click()
setTimeout(() => {
URL.revokeObjectURL(url)
document.body.removeChild(iframe)
}, timeout) // If you can't download it in half an hour, don't download it.
})
.catch(() => {
document.body.removeChild(iframe)
})
} else {
iframe.src = downloadUrl
setTimeout(() => {
document.body.removeChild(iframe)
}, timeout) // If you can't download it in half an hour, don't download it.
a.download = filename
}
a.click()
window.URL.revokeObjectURL(downloadUrl)
}
export function diffObject(object, base) {

View File

@@ -8,16 +8,11 @@ export const GLOBAL_ORG_ID = '00000000-0000-0000-0000-000000000000'
function getPropOrg() {
const orgs = store.getters.usingOrgs
const preOrg = store.getters.preOrg || {}
const preFound = orgs.find((item) => item.id === preOrg.id)
if (preFound) {
return preFound
}
const defaultOrg = orgs.find((item) => item.is_default)
if (defaultOrg) {
return defaultOrg
}
return orgs.filter(item => !item['is_root'] && !item['is_system'])[0]
return orgs.filter(item => !item['is_root'] && item.id !== SYSTEM_ORG_ID)[0]
}
async function change2PropOrg() {
@@ -67,7 +62,7 @@ async function changeOrg(org, reload = true, vm = null) {
}
}
location.hash = '#' + path
setTimeout(() => location.reload(), 500)
setTimeout(() => location.reload(), 400)
}
function hasCurrentOrgPermission() {

View File

@@ -8,10 +8,6 @@ import orgs from '@/api/orgs'
import { getPropView, isViewHasOrgs } from '@/utils/jms'
const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist
const autoEnterOrgs = [
'00000000-0000-0000-0000-000000000001',
'00000000-0000-0000-0000-000000000000'
]
function reject(msg) {
return new Promise((resolve, reject) => reject(msg))
@@ -26,23 +22,7 @@ async function checkLogin({ to, from, next }) {
return await store.dispatch('users/getProfile')
} catch (e) {
Vue.$log.error(e)
// remove currentOrg: System org item
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i)
if (!key.startsWith('jms_current_org_')) {
continue
}
let value = localStorage.getItem(key)
value = JSON.parse(value)
if (!value.is_system) {
continue
}
localStorage.removeItem(key)
}
const status = e.response.status
if (store.getters.currentOrg.autoEnter) {
await store.dispatch('users/setCurrentOrg', store.getters.preOrg)
}
if (status === 401 || status === 403) {
setTimeout(() => {
window.location = process.env.VUE_APP_LOGIN_PATH
@@ -62,10 +42,6 @@ async function getPublicSetting({ to, from, next }, isOpen) {
async function refreshCurrentOrg() {
return orgs.getCurrentOrg().then(org => {
// Root 就不刷新本地的了, 会影响 autoEnter
if (autoEnterOrgs.indexOf(org.id) !== -1) {
return
}
store.dispatch('users/setCurrentOrg', org)
})
}
@@ -84,16 +60,9 @@ async function changeCurrentOrgIfNeed({ to, from, next }) {
Vue.$log.error('Current org is null or not a object: ', currentOrg)
await orgUtil.change2PropOrg({ to, from, next })
}
const globalOrgPath = [
'/console/perms/login-acls/', '/console/users/roles/',
'/console/perms/connect-method-acls/', '/settings/'
]
if (autoEnterOrgs.indexOf(currentOrg.id) !== -1 && currentOrg.autoEnter) {
const delta = new Date().getTime() - currentOrg.autoEnter
const notNeedChange = globalOrgPath.find(path => to.path.indexOf(path) === 0)
if (!notNeedChange && delta > 3000) {
await orgUtil.change2PropOrg({ to, from, next })
}
if (currentOrg.name === 'SystemSetting') {
const preOrg = store.getters.preOrg
await orgUtil.changeOrg(preOrg)
return
}
if (!orgUtil.hasCurrentOrgPermission()) {
@@ -170,24 +139,18 @@ export async function startup({ to, from, next }) {
if (store.getters.inited) {
return true
}
await store.dispatch('app/init')
try {
await store.dispatch('app/init')
// set page title
// await getOpenPublicSetting({ to, from, next })
await getPublicSetting({ to, from, next }, true)
await checkLogin({ to, from, next })
await getPublicSetting({ to, from, next }, false)
await changeCurrentViewIfNeed({ to, from, next })
await changeCurrentOrgIfNeed({ to, from, next })
await generatePageRoutes({ to, from, next })
await checkUserFirstLogin({ to, from, next })
await store.dispatch('assets/getAssetCategories')
} catch (e) {
Vue.$log.error('Startup error: ', e)
}
// set page title
// await getOpenPublicSetting({ to, from, next })
await getPublicSetting({ to, from, next }, true)
await checkLogin({ to, from, next })
await getPublicSetting({ to, from, next }, false)
await changeCurrentViewIfNeed({ to, from, next })
await changeCurrentOrgIfNeed({ to, from, next })
await generatePageRoutes({ to, from, next })
await checkUserFirstLogin({ to, from, next })
await store.dispatch('assets/getAssetCategories')
return true
}

View File

@@ -6,7 +6,6 @@
:account="account"
:show-password-record="false"
:url="secretUrl"
type="template"
:visible.sync="showViewSecretDialog"
/>
</div>
@@ -32,7 +31,7 @@ export default {
tableConfig: {
url: '/api/v1/accounts/account-templates/',
columns: null,
columnsExclude: ['spec_info', 'password_rules', 'push_params'],
columnsExclude: ['spec_info'],
columnsShow: {
min: ['name', 'actions'],
default: ['name', 'username', 'secret_type', 'has_secret', 'privileged', 'actions']

View File

@@ -222,30 +222,6 @@ export default {
getUrlQuery: false
},
extraMoreActions: [
{
name: 'BulkVerify',
title: this.$t('common.BulkVerify'),
type: 'primary',
icon: 'fa fa-link',
can: ({ selectedRows }) =>
this.$hasPerm('assets.test_assetconnectivity') &&
!this.$store.getters.currentOrgIsRoot &&
selectedRows.length > 0 &&
selectedRows[0].auto_config?.ansible_enabled &&
selectedRows[0].auto_config?.ping_enabled,
callback: function({ selectedRows }) {
const ids = selectedRows.map(v => {
return v.id
})
this.$axios.post(
'/api/v1/assets/assets/tasks/',
{ action: 'test', assets: ids }).then(res => {
openTaskPage(res['task'])
}).catch(err => {
this.$message.error(this.$tc('common.bulkVerifyErrorMsg' + ' ' + err))
})
}.bind(this)
},
{
name: 'DeactiveSelected',
title: this.$t('common.BatchDisable'),

View File

@@ -26,7 +26,7 @@ export default {
[this.$t('xpack.Cloud.CloudSource'), ['account', 'regions']],
[this.$t('xpack.Cloud.SaveSetting'), [
'hostname_strategy', 'ip_network_segment_group',
'sync_ip_type', 'is_always_update', 'fully_synchronous', 'release_assets'
'sync_ip_type', 'is_always_update', 'fully_synchronous'
]],
[this.$t('xpack.Cloud.SyncStrategy'), ['strategy']],
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
@@ -68,11 +68,6 @@ export default {
label: this.$t('xpack.Cloud.FullySynchronous'),
helpTips: this.$t('xpack.Cloud.FullySynchronousHelpTips')
},
release_assets: {
type: 'switch',
label: this.$t('xpack.Cloud.ReleaseAssets'),
helpTips: this.$t('xpack.Cloud.ReleaseAssetsHelpTips')
},
regions: {
component: Select2,
el: {

View File

@@ -10,11 +10,13 @@
@click="onSetting"
/>
<Dialog
v-if="isVisible"
width="60%"
:visible.sync="isVisible"
:title="title"
:show-cancel="false"
:show-confirm="false"
:destroy-on-close="true"
@close="onDialogClose"
>
<AutoDataForm
@@ -32,7 +34,7 @@
<script>
import Dialog from '../../../components/Dialog'
import AutoDataForm from '../../../components/Form/AutoDataForm'
import { DynamicInput, Switcher } from '../../../components/Form/FormFields'
import { DynamicInput } from '../../../components/Form/FormFields'
export default {
components: {
@@ -145,9 +147,6 @@ export default {
case 'list':
component = DynamicInput
break
case 'boolean':
component = Switcher
break
}
if (param) {

View File

@@ -100,7 +100,7 @@ export default {
this.data.total_count_job_logs = data?.total_count_job_logs
this.data.total_count_job_logs_running = data?.total_count_job_logs_running
this.data.total_count_job_logs_failed = data?.total_count_job_logs_failed
if (totalCountSession.length > 0) {
if (totalCountSession.length > 1) {
this.chartConfig.secondaryData = totalCountSession
}
}

View File

@@ -16,7 +16,8 @@ export default {
Title,
LineChart
},
props: {},
props: {
},
data() {
return {
loading: false,
@@ -47,10 +48,10 @@ export default {
const activeUsers = data?.dates_metrics_total_count_active_users
const activeAssets = data?.dates_metrics_total_count_active_assets
this.lineChartConfig.datesMetrics = data.dates_metrics_date
if (activeUsers.length > 0) {
if (activeUsers.length > 1) {
this.lineChartConfig.primaryData = activeUsers
}
if (activeAssets.length > 0) {
if (activeAssets.length > 1) {
this.lineChartConfig.secondaryData = activeAssets
}
}
@@ -63,7 +64,6 @@ export default {
margin-top: 16px;
padding: 20px;
background: #fff;
.head {
display: flex;
justify-content: space-between;

View File

@@ -128,8 +128,7 @@ export default {
tip += current.label + '' + current.total + '<br/>'
}
return tip
},
appendToBody: true
}
},
grid: {
top: '60%',

View File

@@ -66,16 +66,7 @@ export default {
},
methods: {
async getResourcesCount() {
return this.$axios.get(
'/api/v1/index/',
{
params: {
total_count_online_sessions: 1,
total_count_online_users: 1,
total_count_today_failed_sessions: 1
}
}
)
return this.$axios.get('/api/v1/index/?total_count=1')
}
}
}

View File

@@ -119,7 +119,7 @@
import { TreeTable } from '@/components'
import Term from '@/components/Widgets/Term'
import Page from '@/layout/components/Page'
import { createJob, getTaskDetail, JobUploadFile } from '@/api/ops'
import { createJob, getJob, getTaskDetail, JobUploadFile } from '@/api/ops'
import { formatFileSize } from '@/utils/common'
import store from '@/store'
@@ -230,9 +230,28 @@ export default {
},
mounted() {
this.enableWS()
this.initData()
},
methods: {
formatFileSize,
async initData() {
this.recoverStatus()
},
recoverStatus() {
if (this.$route.query.taskId) {
this.currentTaskId = this.$route.query.taskId
getTaskDetail(this.currentTaskId).then(data => {
getJob(data.job_id).then(res => {
this.runAsInput.value = res.runas
this.runAsInput.callback(res.runas)
this.executionInfo.status = data['status']
this.executionInfo.timeCost = data['time_cost']
this.setCostTimeInterval()
this.writeExecutionOutput()
})
})
}
},
enableWS() {
const scheme = document.location.protocol === 'https:' ? 'wss' : 'ws'
const port = document.location.port ? ':' + document.location.port : ''
@@ -262,7 +281,7 @@ export default {
}
},
taskStatusStat(summary) {
const { ok = [], failures = [], dark = [], excludes = [], skipped = [] } = summary
const { ok, failures, dark, excludes, skipped } = summary
const failedKeys = Object.keys(failures)
const darkKeys = Object.keys(dark)
@@ -420,7 +439,6 @@ export default {
this.executionInfo.timeCost = 0
this.executionInfo.status = 'running'
this.currentTaskId = res.task_id
this.$router.replace({ query: { taskId: this.currentTaskId, type: 'file_upload' }})
this.setCostTimeInterval()
this.writeExecutionOutput()
}).catch(() => {

View File

@@ -98,7 +98,6 @@ export default {
el: {
baseUrl: '/api/v1/perms/users/self/assets/',
baseNodeUrl: '/api/v1/perms/users/self/nodes/',
typeUrl: '/api/v1/perms/users/self/nodes/children-with-assets/category/tree',
value: []
}
},

View File

@@ -446,7 +446,7 @@ export default {
this.executionInfo.timeCost = 0
this.executionInfo.status = 'running'
this.currentTaskId = res.task_id
this.$router.replace({ query: { taskId: this.currentTaskId, type: 'shortcut_cmd' }})
this.$router.replace({ query: { taskId: this.currentTaskId }})
this.setCostTimeInterval()
this.writeExecutionOutput()
this.setBtn()
@@ -455,7 +455,7 @@ export default {
stop() {
StopJob({ task_id: this.currentTaskId }).then(() => {
this.xterm.write('\x1b[31m' +
this.$tc('ops.StopLogOutput').replace('currentTaskId', this.currentTaskId) + '\x1b[0m')
this.$tc('ops.StopLogOutput').replace('currentTaskId', this.currentTaskId) + '\x1b[0m')
this.xterm.write(this.wrapperError(''))
this.getTaskStatus()
}).catch((e) => {

View File

@@ -105,7 +105,6 @@ export default {
formatter: AmountFormatter,
formatterArgs: {
async: true,
cellValueToRemove: ['@SPEC'],
routeQuery: {
activeTab: 'AssetPermissionUser'
}

View File

@@ -41,7 +41,7 @@ export default {
component: PhoneInput
},
mfa_level: {
disabled: (formValue) => {
hidden: (formValue) => {
return formValue.mfa_level === 2
},
helpText: this.$t('users.HelpText.MFAOfUserFirstLoginPersonalInformationImprovementPage')
@@ -90,7 +90,8 @@ export default {
}
}
},
methods: {}
methods: {
}
}
</script>

View File

@@ -143,7 +143,7 @@ export default {
},
callbacks: {
click: function() {
window.open('/core/auth/profile/mfa/', '_blank')
window.location.href = `/core/auth/profile/mfa/`
}
}
},

View File

@@ -22,7 +22,6 @@ import isFalsey from '@/components/Table/DataTable/compenents/el-data-table/util
import deepmerge from 'deepmerge'
import * as queryUtil from '@/components/Table/DataTable/compenents/el-data-table/utils/query'
import { createSourceIdCache } from '@/api/common'
import { download } from '@/utils/common'
export default {
name: 'CommandList',
@@ -145,7 +144,10 @@ export default {
queryUtil.stringify(query, '=', '&')
url = url + queryStr
this.$log.debug('Export url: ', this.url, '=>', url)
download(url + queryStr)
const a = document.createElement('a')
a.href = url
a.click()
window.URL.revokeObjectURL(url + queryStr)
}
}
},

View File

@@ -55,7 +55,8 @@ export default {
fieldsMeta: {
EMAIL_HOST_USER: {
rules: [
rules.EmailCheck
rules.EmailCheck,
rules.Required
]
},
EMAIL_FROM: {

View File

@@ -12,24 +12,25 @@ export default {
data() {
return {
config: {
initial: {},
initial: {
},
url: '/api/v1/orgs/orgs/',
fields: [
['', ['name', 'comment']]
],
hasSaveContinue: false,
fieldsMeta: {},
fieldsMeta: {
},
onPerformSuccess(res, method) {
const order_params = { params: { order: '-date_created' }}
switch (method) {
case 'post':
this.$store.dispatch('users/addAdminOrg', { id: res.id, name: res.name })
this.$message.success(this.$tc('common.createSuccessMsg'))
return this.$router.push({ name: 'OrganizationList', ...order_params })
return this.$router.push({ name: 'OrganizationList' })
case 'put':
this.$store.dispatch('users/modifyOrg', { id: res.id, name: res.name })
this.$message.success(this.$tc('common.updateSuccessMsg'))
return this.$router.push({ name: 'OrganizationList', ...order_params })
return this.$router.push({ name: 'OrganizationList' })
}
}
}

View File

@@ -19,7 +19,7 @@ export default {
data() {
const commandType = this.$route.query.type || 'es'
return {
successUrl: { name: 'Storage', params: { activeMenu: 'CommandStorage' }},
successUrl: { name: 'TerminalSetting', params: { activeMenu: 'CommandStorage' }},
initial: {
type: commandType,
doc_type: 'command',

View File

@@ -137,14 +137,6 @@ export default {
canCreate: this.$hasPerm('tickets.view_ticket'),
hasBulkDelete: false,
searchConfig: {
default: {
state: {
key: 'state',
label: this.$t('tickets.action'),
value: 'pending',
valueLabel: this.$t('common.Open')
}
},
exclude: ['id', 'title', 'type', 'applicant'],
options: [
{
@@ -188,7 +180,7 @@ export default {
},
{
value: 'relevant_command',
label: this.$t('tickets.ApplyRunCommand')
label: this.$t('tickets.RelevantSystemUser')
}
]
},

View File

@@ -24,7 +24,6 @@
v-model="requestForm.accounts"
:nodes="requestForm.nodes"
:assets="requestForm.assets"
:oid="requestForm.oid"
:show-add-template="false"
style="width: 50% !important"
/>
@@ -45,7 +44,7 @@
<BasicTree
v-model="requestForm.actions"
:tree="treeNodes"
style="width: 100%"
style="width: 30% !important"
/>
</el-form-item>
@@ -84,7 +83,6 @@ export default {
assets: this.object.apply_assets?.map(i => i.id),
accounts: this.object.apply_accounts,
actions: this.object.apply_actions,
oid: this.object.org_id,
apply_date_expired: this.object.apply_date_expired,
apply_date_start: this.object.apply_date_start
},

View File

@@ -48,12 +48,7 @@ export default {
}
],
select2Option: {
url: '/api/v1/users/users/?oid=root',
ajax: {
transformOption: (item) => {
return { label: item.name + '(' + item.username + ')', value: item.id }
}
}
url: '/api/v1/users/users/?oid=root'
},
fields: [
]

View File

@@ -27,7 +27,7 @@
<el-form-item style="float: right">
<template v-if="hasActionPerm">
<el-button
:disabled="isDisabled || object.status.value === 'closed'"
:disabled="object.status.value === 'closed'"
size="small"
type="primary"
@click="handleApprove"
@@ -35,7 +35,7 @@
<i class="fa fa-check" /> {{ $t('tickets.Accept') }}
</el-button>
<el-button
:disabled="isDisabled || object.status.value === 'closed'"
:disabled="object.status.value === 'closed'"
size="small"
type="warning"
@click="handleReject"
@@ -45,12 +45,12 @@
</template>
<el-button
v-if="isSelfTicket"
:disabled="isDisabled || object.status.value === 'closed'"
:disabled="object.status.value === 'closed'"
size="small"
type="danger"
@click="handleClose"
>
<i class="fa fa-times" /> {{ $t('tickets.CancelTicket') }}
<i class="fa fa-times" /> {{ $t('tickets.Close') }}
</el-button>
<el-button
:disabled="object.status.value === 'closed'"
@@ -94,7 +94,6 @@ export default {
},
data() {
return {
isDisabled: false,
comments: '',
type_api: '',
imageUrl: require('@/assets/img/avatar.png'),
@@ -157,35 +156,17 @@ export default {
this.createComment(function() {
})
const url = `/api/v1/tickets/${this.type_api}/${this.object.id}/approve/`
this.$axios.put(url).then(res => {
this.reloadPage()
}).catch(err => {
this.$message.error(err)
}).finally(() => {
this.isDisabled = false
})
this.$axios.put(url).then(res => this.reloadPage()).catch(err => this.$message.error(err))
},
defaultReject() {
this.createComment(function() {
})
const url = `/api/v1/tickets/${this.type_api}/${this.object.id}/reject/`
this.$axios.put(url).then(res => {
this.reloadPage()
}).catch(err => {
this.$message.error(err)
}).finally(() => {
this.isDisabled = false
})
this.$axios.put(url).then(res => this.reloadPage()).catch(err => this.$message.error(err))
},
defaultClose() {
const url = `/api/v1/tickets/${this.type_api}/${this.object.id}/close/`
this.$axios.put(url).then(res => {
this.reloadPage()
}).catch(err => {
this.$message.error(err)
}).finally(() => {
this.isDisabled = false
})
this.$axios.put(url).then(res => this.reloadPage()).catch(err => this.$message.error(err))
},
createComment(successCallback) {
const commentText = this.form.comments
@@ -206,42 +187,17 @@ export default {
}
})
},
handleAction(actionType) {
if (this.isDisabled) {
return
}
this.isDisabled = true
let handler
switch (actionType) {
case 'approve':
handler = this.approve || this.defaultApprove
break
case 'reject':
handler = this.reject || this.defaultReject
break
case 'close':
handler = this.close || this.defaultClose
break
default:
handler = null
break
}
if (handler) {
handler()
} else {
this.$message.error('No handler for action')
}
},
handleApprove() {
this.handleAction('approve')
const handler = this.approve || this.defaultApprove
handler()
},
handleReject() {
this.handleAction('reject')
const handler = this.reject || this.defaultReject
handler()
},
handleClose() {
this.handleAction('close')
const handler = this.close || this.defaultClose
handler()
},
handleComment() {
this.createComment(

View File

@@ -4,6 +4,7 @@
<script>
import { GenericCreateUpdatePage } from '@/layout/components'
import TransSelect from '@/components/Form/FormFields/TransferSelect.vue'
export default {
components: {
@@ -22,6 +23,7 @@ export default {
],
fieldsMeta: {
users: {
component: TransSelect,
el: {
url: '/api/v1/users/users/?fields_size=mini&order=name',
ajax: {
@@ -36,7 +38,8 @@ export default {
}
}
},
methods: {}
methods: {
}
}
</script>

View File

@@ -8,7 +8,6 @@ import { PhoneInput, UserPassword } from '@/components/Form/FormFields'
import rules from '@/components/Form/DataForm/rules'
import { mapGetters } from 'vuex'
import { Select2 } from '@/components'
import store from '@/store'
export default {
components: {
@@ -41,9 +40,6 @@ export default {
return this.$route.params.id || formValue.source !== 'local'
}
},
mfa_level: {
disabled: false
},
email: {
rules: [
rules.EmailCheck,
@@ -152,8 +148,8 @@ export default {
},
hidden: () => {
return !this.$store.getters.hasValidLicense ||
!this.$hasPerm('rbac.add_orgrolebinding') ||
this.$store.getters.currentOrgIsRoot
!this.$hasPerm('rbac.add_orgrolebinding') ||
this.$store.getters.currentOrgIsRoot
},
helpText: this.$t('users.HelpText.OrgRoleHelpText')
},
@@ -216,7 +212,6 @@ export default {
this.fieldsMeta.groups.el.disabled = true
}
await this.setDefaultRoles()
this.disableMFAFieldIfNeed(null)
this.loading = false
},
methods: {
@@ -234,21 +229,11 @@ export default {
if (this.$route.query.clone_from) {
this.user.groups = []
}
this.disableMFAFieldIfNeed(user)
},
async setDefaultRoles() {
const roles = await this.$axios.get('/api/v1/rbac/roles/')
this.initial.system_roles = roles.filter(role => role.name === 'User').map(role => role.id)
this.initial.org_roles = roles.filter(role => role.name === 'OrgUser').map(role => role.id)
},
disableMFAFieldIfNeed(user) {
// SECURITY_MFA_AUTH 0 不开启 1 全局开启 2 管理员开启
const adminUserIsNeed = (user?.is_superuser || user?.is_org_admin) && this.$route.meta.action === 'update' &&
store.getters.publicSettings['SECURITY_MFA_AUTH'] === 2
if (store.getters.publicSettings['SECURITY_MFA_AUTH'] === 1 || adminUserIsNeed) {
this.fieldsMeta['mfa_level'].disabled = true
this.fieldsMeta['mfa_level'].helpText = this.$t('users.GlobalDisableMfaMsg')
}
}
}
}

3659
yarn.lock

File diff suppressed because it is too large Load Diff