mirror of
https://github.com/jumpserver/lina.git
synced 2025-11-07 18:08:50 +00:00
Compare commits
104 Commits
pr@dev@ass
...
v4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0d7143ff7 | ||
|
|
0bfc68fb9c | ||
|
|
fa65d1c8b8 | ||
|
|
faf7abf716 | ||
|
|
b792c18b55 | ||
|
|
a4b59fbb03 | ||
|
|
d99c87f31b | ||
|
|
42afb2e143 | ||
|
|
bcb08f150c | ||
|
|
8640435412 | ||
|
|
66f57af689 | ||
|
|
cdac71876b | ||
|
|
414ff7b8bf | ||
|
|
e50d720e18 | ||
|
|
d1e7822b8f | ||
|
|
f7e6bd0169 | ||
|
|
b3980e56de | ||
|
|
0f8a58209c | ||
|
|
620dcf25a0 | ||
|
|
1bf839ac5a | ||
|
|
65ed7217cd | ||
|
|
a0d3f6096e | ||
|
|
b75f10ec0c | ||
|
|
c45e303127 | ||
|
|
c09d6c96a3 | ||
|
|
da03a92adb | ||
|
|
ef0d0cc260 | ||
|
|
03aa4b60f7 | ||
|
|
668d2e6fc4 | ||
|
|
a0d443b8b0 | ||
|
|
dc2a4d0c54 | ||
|
|
389707a980 | ||
|
|
40922f77b0 | ||
|
|
1702241ccd | ||
|
|
29db60fef5 | ||
|
|
0c897e54a3 | ||
|
|
4596887bf1 | ||
|
|
0a3dc30c85 | ||
|
|
51d24bc8e5 | ||
|
|
1b15a4d043 | ||
|
|
7d3f818242 | ||
|
|
4e26f18d77 | ||
|
|
b22613617a | ||
|
|
e971cbf4a8 | ||
|
|
4672abae35 | ||
|
|
ba36d72602 | ||
|
|
4bfbbba4c5 | ||
|
|
ea038ce43a | ||
|
|
e16b19666c | ||
|
|
c7f5409eb6 | ||
|
|
fdbd7d2222 | ||
|
|
ddbaeeafea | ||
|
|
efb0e9dacb | ||
|
|
f6f8301ad5 | ||
|
|
9a63ae63d4 | ||
|
|
1e007ccda3 | ||
|
|
d1d0b06b53 | ||
|
|
5fb70d2f24 | ||
|
|
b54a95430f | ||
|
|
4d8b4c45af | ||
|
|
a6d642df60 | ||
|
|
2e74f1522f | ||
|
|
fe615e0314 | ||
|
|
09f734e6fc | ||
|
|
3117046342 | ||
|
|
b68aecb5cc | ||
|
|
1c9b155d97 | ||
|
|
75b1be9864 | ||
|
|
615c3c1cf4 | ||
|
|
4d82231af4 | ||
|
|
c6cf6571b6 | ||
|
|
8ea990d070 | ||
|
|
f4a32170d5 | ||
|
|
073508675e | ||
|
|
1d6ca0a93a | ||
|
|
36aea652d6 | ||
|
|
1a42ce90ab | ||
|
|
31a401b55d | ||
|
|
582a84178d | ||
|
|
9b9f7c936c | ||
|
|
2a6100957f | ||
|
|
16606d6a27 | ||
|
|
0a612f50e6 | ||
|
|
fe36fa9390 | ||
|
|
ba109900ec | ||
|
|
ec7768267f | ||
|
|
cc58b374ab | ||
|
|
04ffbb8fd6 | ||
|
|
49880f6739 | ||
|
|
e6f98d58c4 | ||
|
|
fd1f16d43c | ||
|
|
968b2415b1 | ||
|
|
776090d6ba | ||
|
|
3a37952288 | ||
|
|
62b8fc0e3b | ||
|
|
b2028869cb | ||
|
|
5277a725f8 | ||
|
|
f137788c1a | ||
|
|
f7d17c8de7 | ||
|
|
feea70b0be | ||
|
|
04696ef3d6 | ||
|
|
1731f4f788 | ||
|
|
6f25d93909 | ||
|
|
46461ec324 |
@@ -1,4 +1,4 @@
|
||||
FROM node:16.20-bullseye-slim as stage-build
|
||||
FROM node:16.20-bullseye-slim AS stage-build
|
||||
ARG TARGETARCH
|
||||
|
||||
ARG DEPENDENCIES=" \
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"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.15.14",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
|
||||
@@ -157,30 +157,37 @@ export default {
|
||||
$('#m_show_asset_only_current_node').css('color', '#606266')
|
||||
}
|
||||
},
|
||||
|
||||
getAssetsUrl(treeNode) {
|
||||
let url = this.treeSetting?.url || this.url
|
||||
|
||||
const setParam = (param, value, delay) => {
|
||||
setTimeout(() => {
|
||||
url = setUrlParam(url, param, value)
|
||||
})
|
||||
}
|
||||
|
||||
if (treeNode.meta.type === 'node') {
|
||||
const nodeId = treeNode.meta.data.id
|
||||
url = setUrlParam(url, 'node_id', nodeId)
|
||||
url = setUrlParam(url, 'asset_id', '')
|
||||
setParam('node_id', nodeId)
|
||||
setParam('asset_id', '')
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
const assetId = treeNode.meta.data?.id || treeNode.id
|
||||
url = setUrlParam(url, 'node_id', '')
|
||||
url = setUrlParam(url, 'asset_id', assetId)
|
||||
setParam('node_id', '')
|
||||
setParam('asset_id', assetId)
|
||||
} else if (treeNode.meta.type === 'category') {
|
||||
url = setUrlParam(url, 'category', treeNode.meta.category)
|
||||
} else if (treeNode.meta.type === 'type') {
|
||||
url = setUrlParam(url, 'category', treeNode.meta.category)
|
||||
url = setUrlParam(url, 'type', treeNode.meta._type)
|
||||
setParam('category', treeNode.meta.category)
|
||||
setParam('type', treeNode.meta._type)
|
||||
} else if (treeNode.meta.type === 'platform') {
|
||||
url = setUrlParam(url, 'platform', treeNode.id)
|
||||
}
|
||||
const query = this.setTreeUrlQuery()
|
||||
url = query ? `${url}&${query}` : url
|
||||
|
||||
setTimeout(() => {
|
||||
const query = this.setTreeUrlQuery()
|
||||
url = query ? `${url}&${query}` : url
|
||||
this.$set(this.tableConfig, 'url', url)
|
||||
}, 300)
|
||||
})
|
||||
|
||||
if (this.treeSetting.selectSyncToRoute !== false) {
|
||||
setRouterQuery(this, url)
|
||||
|
||||
@@ -134,7 +134,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
<codemirror ref="myCm" v-model="iValue" :options="iOptions" class="editor" />
|
||||
<codemirror
|
||||
ref="myCm"
|
||||
v-model="iValue"
|
||||
:options="iOptions"
|
||||
class="editor"
|
||||
:style="iActions.length > 0 ? { marginLeft: '30px' } : {}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -208,7 +214,7 @@ export default {
|
||||
|
||||
Object.values(actionsObj).forEach(action => {
|
||||
if (action.name === this.$t('RunAs') && action.type === 'input') {
|
||||
rules[action.name] = [{ required: true, message: '请输入运行用户', trigger: 'blur' }]
|
||||
rules[action.name] = [{ required: true, message: this.$t('RequiredRunas'), trigger: 'blur' }]
|
||||
}
|
||||
})
|
||||
|
||||
@@ -373,7 +379,7 @@ $input-border-color: #C0C4CC;
|
||||
}
|
||||
|
||||
.editor {
|
||||
margin-left: 30px;
|
||||
//margin-left: 30px;
|
||||
border: 1px solid var(--color-border);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
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',
|
||||
@@ -197,10 +198,7 @@ export default {
|
||||
})
|
||||
},
|
||||
downloadCsv(url) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
download(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}`)
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog/index.vue'
|
||||
import ImportTable from '@/components/Table/ListTable/TableAction/ImportTable.vue'
|
||||
import { getErrorResponseMsg } from '@/utils/common'
|
||||
import { download, getErrorResponseMsg } from '@/utils/common'
|
||||
import { createSourceIdCache } from '@/api/common'
|
||||
|
||||
export default {
|
||||
@@ -226,10 +226,7 @@ export default {
|
||||
this.$message.success(msg)
|
||||
},
|
||||
downloadCsv(url) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
download(url)
|
||||
},
|
||||
async handleImportConfirm() {
|
||||
await this.$refs['importTable'].performUpload()
|
||||
|
||||
@@ -124,6 +124,9 @@ export default {
|
||||
return this.iHasLeftActions ? 'right' : 'left'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$emit('done')
|
||||
},
|
||||
methods: {
|
||||
handleTagSearch(val) {
|
||||
this.searchTable(val)
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
: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"
|
||||
@@ -73,9 +75,11 @@ export default {
|
||||
return {
|
||||
selectedRows: [],
|
||||
init: false,
|
||||
extraQuery: extraQuery,
|
||||
urlUpdated: {},
|
||||
isDeactivated: false
|
||||
isDeactivated: false,
|
||||
extraQuery: extraQuery,
|
||||
actionInit: this.headerActions.has === false,
|
||||
initQuery: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -203,13 +207,35 @@ export default {
|
||||
}, 500)
|
||||
},
|
||||
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) {
|
||||
const init = this.updateInitQuery(attrs)
|
||||
if (init) {
|
||||
return
|
||||
}
|
||||
this.$log.debug('ListTable: search table', attrs)
|
||||
this.$emit('TagSearch', attrs)
|
||||
this.$refs.dataTable?.$refs.dataTable?.search(attrs, true)
|
||||
|
||||
@@ -234,10 +234,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) {
|
||||
|
||||
@@ -167,7 +167,7 @@ $origin-color: #ffffff;
|
||||
justify-content: space-between;
|
||||
|
||||
.left {
|
||||
height: 100%;
|
||||
//height: 100%;
|
||||
background: $origin-color;
|
||||
color: var(--color-border);
|
||||
|
||||
|
||||
@@ -4,28 +4,29 @@
|
||||
<div class="action-bar">
|
||||
<div class="action">
|
||||
<span>
|
||||
<i :class="[!isShow ? 'fa-eye' : 'fa-eye-slash']" class="fa" @click="onView" />
|
||||
<i class="fa" :class="[!isShow ? 'fa-eye' : 'fa-eye-slash']" @click="onView" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-col :span="span" :style="{'height': height + 'px' }">
|
||||
<el-input
|
||||
v-model="iValue"
|
||||
:rows="rows"
|
||||
autosize
|
||||
:rows="rows"
|
||||
type="textarea"
|
||||
@change="onChange"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col v-show="isShow" :span="span">
|
||||
<VueMarkdown :html="false" :show="true" :source="iValue" class="result-html" />
|
||||
<VueMarkdown class="result-html" :source="sanitizedValue" :html="false" :show="true" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<VueMarkdown v-else :html="false" :source="iValue" class="source" />
|
||||
<VueMarkdown v-else class="source" :html="false" :source="sanitizedValue" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DOMPurify from 'dompurify'
|
||||
import VueMarkdown from 'vue-markdown'
|
||||
|
||||
export default {
|
||||
@@ -55,6 +56,17 @@ 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 => {
|
||||
|
||||
@@ -23,8 +23,18 @@ export default {
|
||||
'publicSettings'
|
||||
]),
|
||||
key() {
|
||||
// 想让创建后回来 List 页面不刷新,但是完全不刷新 table 会不对,所以创建完成后,会更新 order 和 updated
|
||||
// query 去掉这两个,如果变了再刷新
|
||||
const query = {}
|
||||
for (const [k, v] of Object.entries(this.$route.query)) {
|
||||
if (k.includes('updated') || k.includes('order')) {
|
||||
continue
|
||||
}
|
||||
query[k] = v
|
||||
}
|
||||
|
||||
if (this.$route.name.toLowerCase().includes('list')) {
|
||||
return _.trimEnd(this.$route.path, '/')
|
||||
return _.trimEnd(this.$route.path, '/') + '?' + new URLSearchParams(query).toString()
|
||||
} else {
|
||||
return new Date().getTime()
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export default {
|
||||
return this.$t('LicenseExpired')
|
||||
}
|
||||
if (intervalDays < 7) {
|
||||
return this.$t('LicenseWillBe') + this.licenseData.date_expired + this.$t('Expire')
|
||||
return this.$t('LicenseWillBe') + ' ' + this.licenseData.date_expired + ' ' + this.$t('Expire')
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
@@ -205,7 +205,7 @@ export default {
|
||||
hidden: true,
|
||||
component: () => import('@/views/ops/Template/Adhoc/AdhocUpdateCreate'),
|
||||
meta: {
|
||||
title: i18n.t('createAdhoc'),
|
||||
title: i18n.t('AdhocUpdate'),
|
||||
permissions: ['ops.add_adhoc'],
|
||||
activeMenu: '/workbench/ops/templates'
|
||||
}
|
||||
|
||||
BIN
src/styles/icons/cloud.png
Normal file
BIN
src/styles/icons/cloud.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -112,6 +112,11 @@
|
||||
background: url('./icons/gpt.png') no-repeat center left transparent;
|
||||
}
|
||||
|
||||
&.WebCloud_ico_docu {
|
||||
background: url('icons/cloud.png') no-repeat center left transparent;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
&.clickhouse_ico_docu {
|
||||
background: url('./icons/clickhouse.png') no-repeat center left transparent;
|
||||
}
|
||||
|
||||
@@ -217,13 +217,19 @@ export function downloadText(content, filename) {
|
||||
}
|
||||
|
||||
export function download(downloadUrl, filename) {
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.style.display = 'none'
|
||||
document.body.appendChild(iframe)
|
||||
const a = document.createElement('a')
|
||||
a.href = downloadUrl
|
||||
if (filename) {
|
||||
a.download = filename
|
||||
}
|
||||
iframe.contentWindow.document.body.appendChild(a)
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(downloadUrl)
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(iframe)
|
||||
}, 1000 * 60 * 30) // If you can't download it in half an hour, don't download it.
|
||||
}
|
||||
|
||||
export function diffObject(object, base) {
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
const moment = require('moment')
|
||||
|
||||
function getUserLang() {
|
||||
const userLangEN = document.cookie.indexOf('django_language=en')
|
||||
if (userLangEN === -1) {
|
||||
return 'zh-CN'
|
||||
} else {
|
||||
return 'en-US'
|
||||
}
|
||||
}
|
||||
import { getLangCode } from '@/i18n/utils'
|
||||
|
||||
function getTimeUnits(u) {
|
||||
const units = {
|
||||
@@ -16,10 +8,11 @@ function getTimeUnits(u) {
|
||||
'm': '分',
|
||||
's': '秒'
|
||||
}
|
||||
if (getUserLang() === 'zh-CN') {
|
||||
if (getLangCode() === 'zh') {
|
||||
return units[u]
|
||||
} else {
|
||||
return u
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
export function timeOffset(a, b) {
|
||||
|
||||
@@ -164,8 +164,8 @@ export default {
|
||||
},
|
||||
extraMoreActions: [
|
||||
{
|
||||
name: 'BatchRetry',
|
||||
title: this.$t('BatchRetry'),
|
||||
name: 'RetrySelected',
|
||||
title: this.$t('RetrySelected'),
|
||||
type: 'primary',
|
||||
fa: 'fa-retweet',
|
||||
can: ({ selectedRows }) => {
|
||||
|
||||
@@ -164,8 +164,8 @@ export default {
|
||||
},
|
||||
extraMoreActions: [
|
||||
{
|
||||
name: 'BatchRetry',
|
||||
title: this.$t('BatchRetry'),
|
||||
name: 'RetrySelected',
|
||||
title: this.$t('RetrySelected'),
|
||||
type: 'primary',
|
||||
fa: 'fa-retweet',
|
||||
can: ({ selectedRows }) => {
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
@click="onSetting"
|
||||
/>
|
||||
<Dialog
|
||||
v-if="isVisible"
|
||||
:destroy-on-close="true"
|
||||
:show-cancel="false"
|
||||
:show-confirm="false"
|
||||
:title="title"
|
||||
|
||||
@@ -430,7 +430,7 @@ export default {
|
||||
}
|
||||
createJob(data).then(res => {
|
||||
this.executionInfo.timeCost = 0
|
||||
this.executionInfo.status = 'running'
|
||||
this.executionInfo.status = { value: 'running', label: this.$t('Running') }
|
||||
this.currentTaskId = res.task_id
|
||||
this.xtermConfig = { taskId: this.currentTaskId, type: 'shortcut_cmd' }
|
||||
this.setCostTimeInterval()
|
||||
@@ -451,12 +451,12 @@ export default {
|
||||
})
|
||||
},
|
||||
setBtn() {
|
||||
if (this.executionInfo.status !== 'running') {
|
||||
if (this.executionInfo.status.value !== 'running') {
|
||||
clearInterval(this.executionInfo.cancel)
|
||||
this.toolbar.left.run.icon = 'fa fa-play'
|
||||
}
|
||||
this.toolbar.left.run.isVisible = this.executionInfo.status === 'running'
|
||||
this.toolbar.left.stop.isVisible = this.executionInfo.status !== 'running'
|
||||
this.toolbar.left.run.isVisible = this.executionInfo.status.value === 'running'
|
||||
this.toolbar.left.stop.isVisible = this.executionInfo.status.value !== 'running'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -470,9 +470,9 @@ $container-bg-color: #f7f7f7;
|
||||
flex-direction: column;
|
||||
|
||||
.xterm-container {
|
||||
margin-left: 30px;
|
||||
height: calc(100vh - 549px);
|
||||
min-height: 255px;
|
||||
margin-left: 30px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 5px;
|
||||
background-color: $container-bg-color;
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
<span class="status-item">
|
||||
<span>{{ $tc('Status') }}: </span>
|
||||
<span
|
||||
:class="{'status_success':executionInfo.status==='success',
|
||||
'status_warning':executionInfo.status==='timeout',
|
||||
'status_danger':executionInfo.status==='failed'
|
||||
:class="{'status_success':executionInfo.status.value==='success',
|
||||
'status_warning':executionInfo.status.value==='timeout',
|
||||
'status_danger':executionInfo.status.value==='failed'
|
||||
}"
|
||||
>{{ $tc('' + executionInfo.status) }}</span>
|
||||
>{{ $tc('' + executionInfo.status.label) }}</span>
|
||||
</span>
|
||||
<span class="status-item">
|
||||
<span>{{ $tc('TimeDelta') }}: </span>
|
||||
@@ -66,9 +66,7 @@ export default {
|
||||
executionInfo: {
|
||||
type: Object,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
default: {
|
||||
status: 'success'
|
||||
}
|
||||
default: {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="15" :sm="24">
|
||||
<AutoDetailCard :excludes="excludes" :object="object" :url="url" />
|
||||
<AutoDetailCard
|
||||
:excludes="excludes"
|
||||
:object="object"
|
||||
:url="url"
|
||||
:fields="detailFields"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col v-if="hasSummary" :md="9" :sm="24">
|
||||
<IBox
|
||||
@@ -82,6 +87,19 @@ export default {
|
||||
excludes: [
|
||||
'job', 'parameters', 'summary', 'task_id', 'timedelta'
|
||||
],
|
||||
detailFields: [
|
||||
'task_id', 'time_cost',
|
||||
{
|
||||
key: this.$t('IsFinished'),
|
||||
value: this.object.is_finished ? this.$t('Yes') : this.$t('No')
|
||||
},
|
||||
{
|
||||
key: this.$t('IsSuccess'),
|
||||
value: this.object.is_success ? this.$t('Yes') : this.$t('No')
|
||||
},
|
||||
'job_type', 'material', 'org_name',
|
||||
'date_start', 'date_finished', 'date_created'
|
||||
],
|
||||
url: `/api/v1/ops/job-executions/${this.object.id}/`
|
||||
}
|
||||
},
|
||||
@@ -89,11 +107,6 @@ export default {
|
||||
hasSummary() {
|
||||
return this.object.is_finished && Object.keys(this.object.summary).length
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/ops/job-executions/',
|
||||
columnsExclude: [
|
||||
'summary', 'parameters'
|
||||
'summary', 'parameters', 'timedelta'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['material', 'actions'],
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</template>
|
||||
<template slot="table">
|
||||
<div class="transition-box" style="width: calc(100% - 17px);">
|
||||
<el-tabs v-model="activeEditorId" :closable="true" @tab-remove="onCloseEditor">
|
||||
<el-tabs v-model="activeEditorId" :closable="true" class="workspace-tab" @tab-remove="onCloseEditor">
|
||||
<el-tab-pane
|
||||
v-for="(editor,key) in openedEditor"
|
||||
:key="key"
|
||||
@@ -298,6 +298,12 @@ export default {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.workspace-tab{
|
||||
::v-deep .el-tabs__header {
|
||||
margin: 0 0 15px 30px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-tree {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<div slot="tip" class="el-upload__tip">
|
||||
<span :class="{'hasError': hasFileFormatOrSizeError }" />
|
||||
<div v-if="renderError" class="hasError">{{ renderError }}</div>
|
||||
<h5>请上传包含以下示例结构目录的 .zip 压缩文件</h5>
|
||||
<h5>{{ $t('UploadHelpText') }}</h5>
|
||||
<pre style="display:flex; line-height: 1.2em">
|
||||
./
|
||||
├── roles
|
||||
|
||||
@@ -22,6 +22,7 @@ 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',
|
||||
@@ -134,10 +135,7 @@ export default {
|
||||
queryUtil.stringify(query, '=', '&')
|
||||
url = url + queryStr
|
||||
this.$log.debug('Export url: ', this.url, '=>', url)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url + queryStr)
|
||||
download(url + queryStr)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -65,6 +65,7 @@ export default {
|
||||
label: this.$t('DisplayName'),
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
can: vm.$hasPerm('assets.view_asset'),
|
||||
getTitle: ({ row }) => row.host.name,
|
||||
getRoute: ({ row }) => ({
|
||||
name: 'AppletHostDetail',
|
||||
|
||||
@@ -41,7 +41,7 @@ export default {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/terminal/applet-hosts/',
|
||||
columnsExclude: ['info'],
|
||||
columnsExclude: ['info', 'auto_config', 'gathered_info', 'deploy_options'],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: [
|
||||
@@ -52,6 +52,7 @@ export default {
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatterArgs: {
|
||||
can: vm.$hasPerm('assets.view_asset'),
|
||||
getRoute: ({ row }) => {
|
||||
return {
|
||||
name: 'AppletHostDetail',
|
||||
|
||||
@@ -64,7 +64,7 @@ export default {
|
||||
],
|
||||
encryptedFields: ['VAULT_HCP_TOKEN'],
|
||||
fields: [
|
||||
[this.$t('Backend'),
|
||||
[this.$t('Basic'),
|
||||
[
|
||||
'VAULT_ENABLED',
|
||||
'VAULT_HCP_HOST',
|
||||
|
||||
@@ -234,7 +234,7 @@ export default {
|
||||
} else {
|
||||
value = values[key]
|
||||
}
|
||||
if (value) {
|
||||
if (value !== undefined) {
|
||||
form.append(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button size="mini" type="primary" icon="el-icon-setting" @click="visible = !visible"> {{ $t("Settings...") }} </el-button>
|
||||
<el-button size="mini" type="primary" icon="el-icon-setting" @click="visible = !visible"> {{ $t("Setting") }} </el-button>
|
||||
<Dialog
|
||||
v-if="visible"
|
||||
:show-cancel="false"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button size="mini" type="primary" icon="el-icon-setting" @click="visible=true">{{ $t('Settings...') }}</el-button>
|
||||
<el-button size="mini" type="primary" icon="el-icon-setting" @click="visible=true">{{ $t('Setting') }}</el-button>
|
||||
<Dialog
|
||||
v-if="visible"
|
||||
:destroy-on-close="true"
|
||||
|
||||
@@ -110,7 +110,7 @@ export default {
|
||||
canCreate: this.$hasPerm('orgs.add_organization'),
|
||||
extraActions: [
|
||||
{
|
||||
title: this.$t('Settings...'),
|
||||
title: this.$t('Setting'),
|
||||
icon: 'el-icon-setting',
|
||||
callback: () => {
|
||||
this.visible = true
|
||||
|
||||
@@ -64,8 +64,7 @@ export default {
|
||||
method: 'push_account_method',
|
||||
assets: this.asset_ids,
|
||||
nodes: this.node_ids
|
||||
},
|
||||
helpText: this.$t('ViewBlockedIPSHelpText')
|
||||
}
|
||||
}
|
||||
},
|
||||
cleanFormValue(value) {
|
||||
|
||||
@@ -56,6 +56,12 @@ export default {
|
||||
helpText: this.$t('EsIndex')
|
||||
}
|
||||
}
|
||||
},
|
||||
comment: {
|
||||
component: 'el-input',
|
||||
el: {
|
||||
type: 'textarea'
|
||||
}
|
||||
}
|
||||
},
|
||||
getUrl() {
|
||||
|
||||
@@ -64,6 +64,12 @@ export default {
|
||||
},
|
||||
is_default: {
|
||||
hidden: (formValue) => formValue.type === 'sftp'
|
||||
},
|
||||
comment: {
|
||||
component: 'el-input',
|
||||
el: {
|
||||
type: 'textarea'
|
||||
}
|
||||
}
|
||||
},
|
||||
cleanFormValue(values) {
|
||||
|
||||
@@ -52,6 +52,14 @@ export default {
|
||||
el: {
|
||||
hiddenGroup: true
|
||||
}
|
||||
},
|
||||
TERMINAL_MAGNUS_ENABLED: {
|
||||
hidden: () => {
|
||||
return !this.$store.getters.hasValidLicense
|
||||
},
|
||||
el: {
|
||||
hiddenGroup: true
|
||||
}
|
||||
}
|
||||
},
|
||||
getUrl: () => '/api/v1/settings/setting/?category=terminal',
|
||||
|
||||
@@ -43,7 +43,7 @@ export default {
|
||||
hasMoreActions: true,
|
||||
extraMoreActions: [
|
||||
{
|
||||
name: 'BatchApproval',
|
||||
name: 'ApproveSelected',
|
||||
title: this.$t('ApproveSelected'),
|
||||
can: ({ selectedRows }) => { return selectedRows.length > 0 },
|
||||
callback: function({ selectedRows }) {
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
</a>
|
||||
<div class="media-body ">
|
||||
<strong>{{ item.user_display }}</strong>
|
||||
<small class="text-muted">{{ formatTime(item.date_created) }}</small>
|
||||
<br>
|
||||
<small class="text-muted">{{ item.date_created | date }}</small>
|
||||
<MarkDown :value="item.body" />
|
||||
</div>
|
||||
|
||||
@@ -44,6 +44,14 @@ export const treeNodes = [
|
||||
value: 'connect',
|
||||
label: i18n.t('Connect')
|
||||
},
|
||||
{
|
||||
value: 'delete',
|
||||
label: i18n.t('Delete')
|
||||
},
|
||||
{
|
||||
value: 'share',
|
||||
label: i18n.t('Share')
|
||||
},
|
||||
{
|
||||
value: 'updownload',
|
||||
label: i18n.t('UpDownload'),
|
||||
|
||||
@@ -174,8 +174,8 @@ export default {
|
||||
},
|
||||
afterGetFormValue(obj) {
|
||||
if (obj?.id) {
|
||||
obj.org_roles = obj.org_roles.map(({ id }) => id)
|
||||
obj.system_roles = obj.system_roles.map(({ id }) => id)
|
||||
obj.org_roles = obj.org_roles?.map(({ id }) => id)
|
||||
obj.system_roles = obj.system_roles?.map(({ id }) => id)
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
@@ -4292,6 +4292,11 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1:
|
||||
dependencies:
|
||||
domelementtype "^2.2.0"
|
||||
|
||||
dompurify@^3.1.6:
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.1.6.tgz#43c714a94c6a7b8801850f82e756685300a027e2"
|
||||
integrity sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==
|
||||
|
||||
domready@1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.npmmirror.com/domready/-/domready-1.0.8.tgz"
|
||||
|
||||
Reference in New Issue
Block a user