mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-01 15:07:43 +00:00
feat: 拆分ops 和task 菜单
This commit is contained in:
@@ -738,7 +738,8 @@
|
|||||||
"SessionsAudit": "Sessions audit",
|
"SessionsAudit": "Sessions audit",
|
||||||
"SessionList": "Session list",
|
"SessionList": "Session list",
|
||||||
"BatchCommand": "Batch Command",
|
"BatchCommand": "Batch Command",
|
||||||
"BatchCommandLog": "Batch Command Logs",
|
"BatchScript": "Batch Script",
|
||||||
|
"tasksLog": "Batch Command Logs",
|
||||||
"CeleryTaskLog": "Celery task log",
|
"CeleryTaskLog": "Celery task log",
|
||||||
"CommandExecutions": "CommandExecutions ",
|
"CommandExecutions": "CommandExecutions ",
|
||||||
"CommandFilterCreate": "Command filter create",
|
"CommandFilterCreate": "Command filter create",
|
||||||
@@ -787,7 +788,8 @@
|
|||||||
"FtpLog": "FTP Logs",
|
"FtpLog": "FTP Logs",
|
||||||
"GatewayCreate": "Gateway create",
|
"GatewayCreate": "Gateway create",
|
||||||
"GatewayUpdate": "Gateway update",
|
"GatewayUpdate": "Gateway update",
|
||||||
"JobCenter": "Devops",
|
"TaskCenter": "Task",
|
||||||
|
"JobCenter": "Job",
|
||||||
"LabelCreate": "Label create",
|
"LabelCreate": "Label create",
|
||||||
"LabelList": "Labels",
|
"LabelList": "Labels",
|
||||||
"LabelUpdate": "Label update",
|
"LabelUpdate": "Label update",
|
||||||
|
@@ -751,7 +751,7 @@
|
|||||||
"TicketsTodo": "To-doオーダー",
|
"TicketsTodo": "To-doオーダー",
|
||||||
"TicketsDone": "すでに勤務単",
|
"TicketsDone": "すでに勤務単",
|
||||||
"TicketsNew": "ワークオーダーを提出する",
|
"TicketsNew": "ワークオーダーを提出する",
|
||||||
"BatchCommandLog": "一括コマンド",
|
"tasksLog": "一括コマンド",
|
||||||
"CeleryTaskLog": "Celeryタスクログ",
|
"CeleryTaskLog": "Celeryタスクログ",
|
||||||
"CommandExecutions": "コマンド実行",
|
"CommandExecutions": "コマンド実行",
|
||||||
"CommandFilterCreate": "コマンドフィルタの作成",
|
"CommandFilterCreate": "コマンドフィルタの作成",
|
||||||
|
@@ -766,10 +766,11 @@
|
|||||||
"LogsAudit": "日志审计",
|
"LogsAudit": "日志审计",
|
||||||
"SessionList": "会话记录",
|
"SessionList": "会话记录",
|
||||||
"BatchCommand": "批量命令",
|
"BatchCommand": "批量命令",
|
||||||
|
"BatchScript": "批量脚本",
|
||||||
"TicketsTodo": "待办工单",
|
"TicketsTodo": "待办工单",
|
||||||
"TicketsDone": "已办工单",
|
"TicketsDone": "已办工单",
|
||||||
"TicketsNew": "提交工单",
|
"TicketsNew": "提交工单",
|
||||||
"BatchCommandLog": "批量命令",
|
"tasksLog": "批量命令",
|
||||||
"CeleryTaskLog": "Celery任务日志",
|
"CeleryTaskLog": "Celery任务日志",
|
||||||
"CommandExecutions": "命令执行",
|
"CommandExecutions": "命令执行",
|
||||||
"CommandFilterCreate": "创建命令过滤器",
|
"CommandFilterCreate": "创建命令过滤器",
|
||||||
@@ -820,6 +821,7 @@
|
|||||||
"FtpLog": "FTP日志",
|
"FtpLog": "FTP日志",
|
||||||
"GatewayCreate": "创建网关",
|
"GatewayCreate": "创建网关",
|
||||||
"GatewayUpdate": "更新网关",
|
"GatewayUpdate": "更新网关",
|
||||||
|
"TaskCenter": "任务中心",
|
||||||
"JobCenter": "作业中心",
|
"JobCenter": "作业中心",
|
||||||
"LabelCreate": "创建标签",
|
"LabelCreate": "创建标签",
|
||||||
"LabelList": "标签管理",
|
"LabelList": "标签管理",
|
||||||
|
@@ -30,10 +30,10 @@ export default [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'command-execution-log',
|
path: 'command-execution-log',
|
||||||
name: 'BatchCommandLog',
|
name: 'tasksLog',
|
||||||
component: () => import('@/views/audits/CommandExecutionList'),
|
component: () => import('@/views/audits/CommandExecutionList'),
|
||||||
meta: {
|
meta: {
|
||||||
title: i18n.t('route.BatchCommandLog'),
|
title: i18n.t('route.tasksLog'),
|
||||||
permissions: ['ops.view_commandexecution']
|
permissions: ['ops.view_commandexecution']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ import i18n from '@/i18n/i18n'
|
|||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: '/ops/celery/task/:id/log/',
|
path: '/ops/celery/task/:id/log/',
|
||||||
component: () => import('@/views/ops/CeleryTaskLog'),
|
component: () => import('@/views/tasks/CeleryTaskLog'),
|
||||||
name: 'CeleryTaskLog',
|
name: 'CeleryTaskLog',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
meta: {
|
meta: {
|
||||||
@@ -17,7 +17,7 @@ export default [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/ops/task/task/:id/log/',
|
path: '/ops/task/task/:id/log/',
|
||||||
component: () => import('@/views/ops/CeleryTaskLog'),
|
component: () => import('@/views/tasks/CeleryTaskLog'),
|
||||||
name: 'TaskLog',
|
name: 'TaskLog',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
meta: {
|
meta: {
|
||||||
|
@@ -6,7 +6,7 @@ import store from '@/store'
|
|||||||
import UsersRoute from './users'
|
import UsersRoute from './users'
|
||||||
import AssetsRoute from './assets'
|
import AssetsRoute from './assets'
|
||||||
import PermsRoute from './perms'
|
import PermsRoute from './perms'
|
||||||
import OpsRoutes from './ops'
|
import TaskRoutes from './tasks'
|
||||||
import AclRoutes from './acls'
|
import AclRoutes from './acls'
|
||||||
import AccountRoutes from './accounts'
|
import AccountRoutes from './accounts'
|
||||||
|
|
||||||
@@ -88,14 +88,14 @@ export default {
|
|||||||
children: AclRoutes
|
children: AclRoutes
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/console/ops',
|
path: '/console/tasks',
|
||||||
component: empty,
|
component: empty,
|
||||||
name: 'JobCenter',
|
name: 'TaskCenter',
|
||||||
meta: {
|
meta: {
|
||||||
title: i18n.t('route.JobCenter'),
|
title: i18n.t('route.TaskCenter'),
|
||||||
icon: 'coffee'
|
icon: 'tasks'
|
||||||
},
|
},
|
||||||
children: OpsRoutes
|
children: TaskRoutes
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -1,64 +0,0 @@
|
|||||||
import i18n from '@/i18n/i18n'
|
|
||||||
import { BASE_URL } from '@/utils/common'
|
|
||||||
import empty from '@/layout/empty'
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
path: 'tasks',
|
|
||||||
component: empty,
|
|
||||||
meta: { title: i18n.t('route.TaskList') },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
name: 'TaskList',
|
|
||||||
component: () => import('@/views/ops/TaskList'),
|
|
||||||
meta: { title: i18n.t('route.TaskList'), permissions: [] }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ':id',
|
|
||||||
component: () => import('@/views/ops/TaskDetail'),
|
|
||||||
name: 'TaskDetail',
|
|
||||||
hidden: true,
|
|
||||||
meta: { title: i18n.t('route.TaskDetail'), permissions: [] }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'adhoc/:id',
|
|
||||||
component: () => import('@/views/ops/TaskDetail/AdhocDetail'),
|
|
||||||
name: 'AdhocDetail',
|
|
||||||
hidden: true,
|
|
||||||
meta: {
|
|
||||||
title: i18n.t('route.TaskDetail'),
|
|
||||||
permissions: ['ops.view_adhoc'],
|
|
||||||
activeMenu: '/ops/tasks'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'executions/:id',
|
|
||||||
component: () => import('@/views/ops/TaskDetail/HistoryExecutionDetail'),
|
|
||||||
name: 'HistoryExecutionDetail',
|
|
||||||
hidden: true,
|
|
||||||
meta: {
|
|
||||||
title: i18n.t('route.TaskDetail'),
|
|
||||||
permissions: ['ops.view_adhocexecution'],
|
|
||||||
activeMenu: '/console/ops/tasks'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'command-executions/create',
|
|
||||||
name: 'BatchCommand',
|
|
||||||
component: () => import('@/views/ops/CommandExecution'),
|
|
||||||
meta: {
|
|
||||||
title: i18n.t('route.BatchCommand'),
|
|
||||||
permissions: ['ops.add_adhocexecution'],
|
|
||||||
hidden: ({ settings }) => !settings['SECURITY_COMMAND_EXECUTION']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: `${BASE_URL}/core/flower/?_=${Date.now()}`,
|
|
||||||
name: 'TaskMonitor',
|
|
||||||
// component: () => window.open(`/core/flower?_=${Date.now()}`),
|
|
||||||
meta: { title: i18n.t('route.TaskMonitor'), permissions: ['ops.view_taskmonitor'] }
|
|
||||||
}
|
|
||||||
]
|
|
32
src/router/console/tasks.js
Normal file
32
src/router/console/tasks.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import i18n from '@/i18n/i18n'
|
||||||
|
import { BASE_URL } from '@/utils/common'
|
||||||
|
import empty from '@/layout/empty'
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: 'tasks',
|
||||||
|
component: empty,
|
||||||
|
meta: { title: i18n.t('route.TaskList') },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: 'TaskList',
|
||||||
|
component: () => import('@/views/tasks/TaskList'),
|
||||||
|
meta: { title: i18n.t('route.TaskList'), permissions: [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':id',
|
||||||
|
component: () => import('@/views/tasks/TaskDetail'),
|
||||||
|
name: 'TaskDetail',
|
||||||
|
hidden: true,
|
||||||
|
meta: { title: i18n.t('route.TaskDetail'), permissions: [] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${BASE_URL}/core/flower/?_=${Date.now()}`,
|
||||||
|
name: 'TaskMonitor',
|
||||||
|
// component: () => window.open(`/core/flower?_=${Date.now()}`),
|
||||||
|
meta: { title: i18n.t('route.TaskMonitor'), permissions: ['ops.view_taskmonitor'] }
|
||||||
|
}
|
||||||
|
]
|
@@ -42,26 +42,7 @@ export default {
|
|||||||
permissions: ['perms.view_myassets']
|
permissions: ['perms.view_myassets']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/workbench/ops',
|
|
||||||
component: empty,
|
|
||||||
meta: {
|
|
||||||
permissions: ['ops.add_commandexecution'],
|
|
||||||
hidden: ({ settings }) => !settings['SECURITY_COMMAND_EXECUTION']
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
name: 'CommandExecutions',
|
|
||||||
component: () => import('@/views/ops/CommandExecution'),
|
|
||||||
meta: {
|
|
||||||
title: i18n.t('route.BatchCommand'),
|
|
||||||
icon: 'terminal',
|
|
||||||
permissions: ['ops.add_commandexecution']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: `external-luna`,
|
path: `external-luna`,
|
||||||
component: empty,
|
component: empty,
|
||||||
@@ -97,6 +78,38 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/workbench/ops',
|
||||||
|
component: empty,
|
||||||
|
name: 'JobCenter',
|
||||||
|
meta: {
|
||||||
|
title: i18n.t('route.JobCenter'),
|
||||||
|
icon: 'coffee',
|
||||||
|
permissions: []
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'a',
|
||||||
|
name: 'CommandExecutions2',
|
||||||
|
component: () => import('@/views/ops/Command'),
|
||||||
|
meta: {
|
||||||
|
title: i18n.t('route.BatchCommand'),
|
||||||
|
icon: 'terminal',
|
||||||
|
permissions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: 'CommandExecutions',
|
||||||
|
component: () => import('@/views/ops/Command'),
|
||||||
|
meta: {
|
||||||
|
title: i18n.t('route.BatchScript'),
|
||||||
|
icon: 'book',
|
||||||
|
permissions: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
13
src/views/ops/Command.vue
Normal file
13
src/views/ops/Command.vue
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<div />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Command'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@@ -1,279 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Page>
|
|
||||||
<el-collapse-transition>
|
|
||||||
<div style="display: flex;justify-items: center; flex-wrap: nowrap;justify-content:space-between;">
|
|
||||||
<div v-show="iShowTree" :style="iShowTree?('width:250px;'):('width:0;')" class="transition-box">
|
|
||||||
<AutoDataZTree
|
|
||||||
ref="AutoDataZTree"
|
|
||||||
:key="DataZTree"
|
|
||||||
:setting="treeSetting"
|
|
||||||
class="auto-data-ztree"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div :style="iShowTree?('display: flex;width: calc(100% - 250px);'):('display: flex;width:100%;')">
|
|
||||||
<div class="mini">
|
|
||||||
<div style="display:block" class="mini-button" @click="iShowTree=!iShowTree">
|
|
||||||
<i v-show="iShowTree" class="fa fa-angle-left fa-x" /><i v-show="!iShowTree" class="fa fa-angle-right fa-x" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<IBox class="transition-box" style="width: calc(100% - 17px);">
|
|
||||||
<Term ref="xterm" />
|
|
||||||
<div style="display: flex;margin-top:10px;justify-content: space-between">
|
|
||||||
<div>
|
|
||||||
<CodeMirror :options="codeMirrorOptions" @change="handleActionChange" />
|
|
||||||
</div>
|
|
||||||
<div style="display: flex;flex-direction: column ;justify-content: space-between">
|
|
||||||
<el-select v-model="selectedSystemUser" :placeholder="this.$t('ops.PleaseSelect')" @change="handleSystemUserChange">
|
|
||||||
<el-option
|
|
||||||
v-for="item in options"
|
|
||||||
:key="item.id"
|
|
||||||
:disabled="item.protocol !== 'ssh' || item.login_mode!== 'auto'"
|
|
||||||
:label="`${item.name}(${item.username})`"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
<el-button type="primary" size="small" @click="execute">{{ this.$t('ops.Execute') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</IBox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-collapse-transition>
|
|
||||||
</Page>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import AutoDataZTree from '@/components/AutoDataZTree'
|
|
||||||
import Term from '@/components/Term'
|
|
||||||
import IBox from '@/components/IBox'
|
|
||||||
import CodeMirror from '@/components/CodeMirror'
|
|
||||||
import Page from '@/layout/components/Page'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'CommandExecution',
|
|
||||||
components: {
|
|
||||||
Term,
|
|
||||||
AutoDataZTree,
|
|
||||||
IBox,
|
|
||||||
Page,
|
|
||||||
CodeMirror
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
DataZTree: 0,
|
|
||||||
codeMirrorOptions: {
|
|
||||||
lineNumbers: true,
|
|
||||||
lineWrapping: true,
|
|
||||||
mode: 'shell'
|
|
||||||
},
|
|
||||||
treeSetting: {
|
|
||||||
treeUrl: '',
|
|
||||||
showRefresh: true,
|
|
||||||
showMenu: false,
|
|
||||||
check: {
|
|
||||||
enable: true
|
|
||||||
},
|
|
||||||
view: {
|
|
||||||
dblClickExpand: false,
|
|
||||||
showLine: true
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
simpleData: {
|
|
||||||
enable: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
edit: {
|
|
||||||
enable: true,
|
|
||||||
showRemoveBtn: false,
|
|
||||||
showRenameBtn: false,
|
|
||||||
drag: {
|
|
||||||
isCopy: true,
|
|
||||||
isMove: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: {
|
|
||||||
onCheck: this.onCheck.bind(this),
|
|
||||||
onClick: this.onClick.bind(this),
|
|
||||||
onSelected: this.onSelected.bind(this)
|
|
||||||
},
|
|
||||||
async: {
|
|
||||||
enable: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
iShowTree: true,
|
|
||||||
actions: '',
|
|
||||||
options: [],
|
|
||||||
selectedSystemUser: '',
|
|
||||||
basicUrl: '/api/v1/perms/users/nodes-with-assets/tree/?cache_policy=1',
|
|
||||||
ws: '',
|
|
||||||
wsConnected: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
zTree() {
|
|
||||||
return this.$refs.AutoDataZTree.$refs.dataztree.$refs.ztree.zTree
|
|
||||||
},
|
|
||||||
xterm() {
|
|
||||||
return this.$refs.xterm.xterm
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.$axios.get('/api/v1/perms/system-users-permission/').then(res => {
|
|
||||||
if (res.length === 0) {
|
|
||||||
this.handleSystemUserChange('')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for (const i in res) {
|
|
||||||
// :disabled="item.protocol !== 'ssh'&& item.login_mode!=='auto'"
|
|
||||||
if (res[i].protocol === 'ssh' && res[i].login_mode === 'auto') {
|
|
||||||
this.handleSystemUserChange(res[i].id)
|
|
||||||
this.selectedSystemUser = res[i].id
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.options = res
|
|
||||||
})
|
|
||||||
this.xterm.write(this.$t('ops.selectAssetsMessage'))
|
|
||||||
this.enableWS()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleActionChange(val) {
|
|
||||||
this.actions = val
|
|
||||||
},
|
|
||||||
onClick(event, treeId, treeNode, clickFlag) {
|
|
||||||
// if (treeNode.meta.type === 'asset') {
|
|
||||||
// const protocolsStr = treeNode.meta.data.protocols + ''
|
|
||||||
// if (protocolsStr.indexOf('ssh/') === -1) {
|
|
||||||
// // Don't Support SSH
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
onSelected(event, treeNode) {
|
|
||||||
|
|
||||||
},
|
|
||||||
handleSystemUserChange(id) {
|
|
||||||
this.treeSetting.treeUrl = `${this.basicUrl}&system_user=${id}`
|
|
||||||
this.xterm.clear()
|
|
||||||
this.DataZTree++
|
|
||||||
},
|
|
||||||
getSelectedAssetsNode() {
|
|
||||||
const nodes = this.$refs.AutoDataZTree.$refs.dataztree.$refs.ztree.getCheckedNodes()
|
|
||||||
const assetsNodeId = []
|
|
||||||
const assetsNode = []
|
|
||||||
nodes.forEach(function(node) {
|
|
||||||
if (node.meta.type === 'asset' && !node.isHidden) {
|
|
||||||
const protocolsStr = node.meta.data.protocols + ''
|
|
||||||
if (assetsNodeId.indexOf(node.id) === -1 && protocolsStr.indexOf('ssh') > -1) {
|
|
||||||
assetsNodeId.push(node.id)
|
|
||||||
assetsNode.push(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return assetsNode
|
|
||||||
},
|
|
||||||
onCheck(e, treeId, treeNode) {
|
|
||||||
const nodes = this.getSelectedAssetsNode()
|
|
||||||
const nodes_names = nodes.map(function(node) {
|
|
||||||
return node.name
|
|
||||||
})
|
|
||||||
let message = this.$t('ops.selectedAssets')
|
|
||||||
message += nodes_names.join(', ')
|
|
||||||
message += '\r\n'
|
|
||||||
message += this.$t('ops.inTotal') + `:${nodes_names.length} \r\n`
|
|
||||||
this.xterm.clear()
|
|
||||||
this.xterm.write(message)
|
|
||||||
},
|
|
||||||
enableWS() {
|
|
||||||
const scheme = document.location.protocol === 'https:' ? 'wss' : 'ws'
|
|
||||||
const port = document.location.port ? ':' + document.location.port : ''
|
|
||||||
const url = '/ws/ops/tasks/log/'
|
|
||||||
const wsURL = scheme + '://' + document.location.hostname + port + url
|
|
||||||
// const failOverPort = '8070'
|
|
||||||
// const failOverWsURL = scheme + '://' + document.location.hostname + ':' + failOverPort + url
|
|
||||||
this.ws = new WebSocket(wsURL)
|
|
||||||
this.ws.onerror = (e) => {
|
|
||||||
this.xterm.write(this.wrapperError('Connect websocket server error'))
|
|
||||||
}
|
|
||||||
this.setWsCallback()
|
|
||||||
},
|
|
||||||
setWsCallback() {
|
|
||||||
this.ws.onmessage = (e) => {
|
|
||||||
const data = JSON.parse(e.data)
|
|
||||||
let message = data.message
|
|
||||||
message = message.replace(/Task ops\.tasks\.run_command_execution.*/, '')
|
|
||||||
this.xterm.write(message)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
wrapperError(msg) {
|
|
||||||
return `\r\n${msg}\r\n`
|
|
||||||
},
|
|
||||||
writeExecutionOutput(taskId) {
|
|
||||||
let msg = this.$t('assets.Pending')
|
|
||||||
this.xterm.write(msg)
|
|
||||||
msg = JSON.stringify({ task: taskId })
|
|
||||||
this.ws.send(msg)
|
|
||||||
},
|
|
||||||
execute() {
|
|
||||||
const size = 'rows=' + this.xterm.rows + '&cols=' + this.xterm.cols
|
|
||||||
const url = '/api/v1/ops/command-executions/?' + size
|
|
||||||
const runAs = this.selectedSystemUser
|
|
||||||
const command = this.actions
|
|
||||||
const hosts = this.getSelectedAssetsNode().map(function(node) {
|
|
||||||
return node.id
|
|
||||||
})
|
|
||||||
if (hosts.length === 0) {
|
|
||||||
this.xterm.write(this.wrapperError(this.$t('assets.UnselectedAssets')))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!command) {
|
|
||||||
this.xterm.write(this.wrapperError(this.$t('assets.NoInputCommand')))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!runAs) {
|
|
||||||
this.xterm.write(this.wrapperError(this.$t('assets.NoSystemUserWasSelected')))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const data = {
|
|
||||||
hosts: hosts,
|
|
||||||
run_as: runAs,
|
|
||||||
command: command
|
|
||||||
}
|
|
||||||
this.$axios.post(
|
|
||||||
url, data
|
|
||||||
).then(res => {
|
|
||||||
this.writeExecutionOutput(res.id)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.mini-button{
|
|
||||||
width: 12px;
|
|
||||||
float: right;
|
|
||||||
text-align: center;
|
|
||||||
padding: 5px 0;
|
|
||||||
background-color: var(--color-primary);
|
|
||||||
border-color: var(--color-primary);
|
|
||||||
color: #FFFFFF;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
.el-tree{
|
|
||||||
background-color: inherit !important;
|
|
||||||
}
|
|
||||||
.mini{
|
|
||||||
margin-right: 5px;
|
|
||||||
width: 12px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.auto-data-ztree {
|
|
||||||
overflow: auto;
|
|
||||||
/*border-right: solid 1px red;*/
|
|
||||||
}
|
|
||||||
.vue-codemirror-wrap ::v-deep .CodeMirror{
|
|
||||||
width: 600px;
|
|
||||||
height: 100px;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -1,138 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :md="14" :sm="24">
|
|
||||||
<DetailCard :title="cardTitle" :items="detailCardItems" />
|
|
||||||
</el-col>
|
|
||||||
<el-col :md="10" :sm="24">
|
|
||||||
<RunInfoCard type="danger" style="margin-top: 15px" v-bind="RunFailedConfig" />
|
|
||||||
<RunInfoCard type="info" v-bind="RunSuccessConfig" style="margin-top: 15px" />
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import DetailCard from '@/components/DetailCard/index'
|
|
||||||
import { toSafeLocalDateStr } from '@/utils/common'
|
|
||||||
import RunInfoCard from '../../RunInfoCard'
|
|
||||||
import { toLastFailureDisplay, toLastSucessDisplay } from '../business'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'AdhocDetail',
|
|
||||||
components: {
|
|
||||||
DetailCard,
|
|
||||||
RunInfoCard
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
object: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
RunSuccessConfig: {
|
|
||||||
icon: 'fa-info',
|
|
||||||
title: this.$t('ops.lastRunSuccessHosts'),
|
|
||||||
contents: toLastSucessDisplay(this.object.latest_execution)
|
|
||||||
},
|
|
||||||
RunFailedConfig: {
|
|
||||||
icon: 'fa-info',
|
|
||||||
title: this.$t('ops.lastRunFailedHosts'),
|
|
||||||
contents: toLastFailureDisplay(this.object.latest_execution)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
cardTitle() {
|
|
||||||
return `${this.object.task_name}: ${this.object.short_id}`
|
|
||||||
},
|
|
||||||
detailCardItems() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: this.$t('ops.hosts'),
|
|
||||||
value: JSON.stringify(this.object.hosts.length)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.pattern'),
|
|
||||||
value: this.object.pattern
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.options'),
|
|
||||||
value: this.disPlayOptions(this.object.options)
|
|
||||||
// value: this.object.options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.runAs'),
|
|
||||||
value: this.disPlayRunAs(this.object.run_as_admin, this.object.run_as)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.become'),
|
|
||||||
value: this.object.become_display
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('common.createBy'),
|
|
||||||
value: this.object.created_by
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('common.dateCreated'),
|
|
||||||
value: toSafeLocalDateStr(this.object.date_created)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.runTimes'),
|
|
||||||
value: this.object.run_times
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.lastRun'),
|
|
||||||
value: this.object.latest_execution.last_run
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.timeDelta'),
|
|
||||||
value: this.object.latest_execution.timedelta
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.isFinished'),
|
|
||||||
value: this.object.latest_execution.is_finished
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.isSuccess'),
|
|
||||||
value: this.object.latest_execution.is_success
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('ops.tasks'),
|
|
||||||
value: this.toContentsDisplay(this.object.tasks),
|
|
||||||
formatter(row, value) {
|
|
||||||
return (<div>{
|
|
||||||
value.map((content) => {
|
|
||||||
return <div>{ content }</div>
|
|
||||||
})}
|
|
||||||
</div>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
disPlayRunAs(run_as_admin, run_as) {
|
|
||||||
if (run_as_admin) {
|
|
||||||
return 'Admin'
|
|
||||||
}
|
|
||||||
return run_as
|
|
||||||
},
|
|
||||||
disPlayOptions(options) {
|
|
||||||
return options.replace(/:/g, '=').replace(/'/g, '').replace('{', '').replace('}', '')
|
|
||||||
},
|
|
||||||
toContentsDisplay(contents) {
|
|
||||||
const lines = []
|
|
||||||
for (let i = 0; i < contents.length; i++) {
|
|
||||||
const content = contents[i]
|
|
||||||
lines.push(`${i}. ${content.name} ::: ${content.action.module}`)
|
|
||||||
}
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@@ -1,106 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ListTable :table-config="tableConfig" :header-actions="headerActions" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ListTable from '@/components/ListTable'
|
|
||||||
import { ActionsFormatter } from '@/components/TableFormatters'
|
|
||||||
import { toSafeLocalDateStr } from '@/utils/common'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'AdhocExecutionHistory',
|
|
||||||
components: {
|
|
||||||
ListTable
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
tableConfig: {
|
|
||||||
url: `/api/v1/ops/adhoc-executions/?adhoc=${this.$route.params.id}`,
|
|
||||||
columns: [
|
|
||||||
'date_start', 'stat', 'ratio', 'is_finished', 'is_success', 'timedelta', 'adhoc_short_id', 'actions'
|
|
||||||
],
|
|
||||||
columnsMeta: {
|
|
||||||
date_start: {
|
|
||||||
formatter: function(row) {
|
|
||||||
return toSafeLocalDateStr(row.date_start)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stat: {
|
|
||||||
label: this.$t('ops.stat'),
|
|
||||||
align: 'center',
|
|
||||||
width: '100px',
|
|
||||||
formatter: function(row) {
|
|
||||||
const summary = <div>
|
|
||||||
<span class='text-primary'>{row.stat.success}</span>/
|
|
||||||
<span class='text-danger'>{row.stat.failed}</span>/
|
|
||||||
<span>{row.stat.total}</span>
|
|
||||||
</div>
|
|
||||||
return summary
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ratio: {
|
|
||||||
label: this.$t('ops.ratio'),
|
|
||||||
align: 'center',
|
|
||||||
width: '80px',
|
|
||||||
formatter: function(row) {
|
|
||||||
const ratio = (row.stat.success / row.stat.total) * 100
|
|
||||||
if (ratio === 100) {
|
|
||||||
return <span class='text-navy'>{ratio + '%'}</span>
|
|
||||||
}
|
|
||||||
return <span class='text-danger'>{ratio + '%'}</span>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
is_finished: {
|
|
||||||
align: 'center',
|
|
||||||
width: '100px',
|
|
||||||
label: this.$t('ops.isFinished')
|
|
||||||
},
|
|
||||||
is_success: {
|
|
||||||
align: 'center',
|
|
||||||
width: '100px',
|
|
||||||
label: this.$t('ops.isSuccess')
|
|
||||||
},
|
|
||||||
timedelta: {
|
|
||||||
label: this.$t('ops.time'),
|
|
||||||
width: '100px',
|
|
||||||
formatter: function(row) {
|
|
||||||
return row.timedelta.toFixed(2) + 's'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
adhoc_short_id: {
|
|
||||||
label: this.$t('ops.version')
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
prop: 'id',
|
|
||||||
formatter: ActionsFormatter,
|
|
||||||
formatterArgs: {
|
|
||||||
hasEdit: false,
|
|
||||||
hasDelete: false,
|
|
||||||
hasClone: false,
|
|
||||||
hasUpdate: false,
|
|
||||||
extraActions: [
|
|
||||||
{
|
|
||||||
name: 'detail',
|
|
||||||
title: this.$t('ops.detail'),
|
|
||||||
type: 'primary',
|
|
||||||
callback: function({ row, tableData }) {
|
|
||||||
return this.$router.push({ name: 'HistoryExecutionDetail', params: { id: row.id }})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
headerActions: {
|
|
||||||
hasLeftActions: false,
|
|
||||||
hasRightActions: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@@ -1,47 +0,0 @@
|
|||||||
<template>
|
|
||||||
<GenericDetailPage :object.sync="AdhocDetail" :active-menu.sync="config.activeMenu" v-bind="config" v-on="$listeners">
|
|
||||||
<keep-alive>
|
|
||||||
<component :is="config.activeMenu" :object="AdhocDetail" />
|
|
||||||
</keep-alive>
|
|
||||||
</GenericDetailPage>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { GenericDetailPage, TabPage } from '@/layout/components'
|
|
||||||
import AdhocExecutionHistory from './AdhocExecutionHistory'
|
|
||||||
import AdhocDetail from './AdhocDetail'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
GenericDetailPage,
|
|
||||||
AdhocExecutionHistory,
|
|
||||||
AdhocDetail,
|
|
||||||
TabPage
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
AdhocDetail: {},
|
|
||||||
config: {
|
|
||||||
activeMenu: 'AdhocDetail',
|
|
||||||
title: this.$t('ops.taskDetail'),
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
title: this.$t('ops.versionDetail'),
|
|
||||||
name: 'AdhocDetail'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.$t('ops.versionRunExecution'),
|
|
||||||
name: 'AdhocExecutionHistory',
|
|
||||||
hidden: () => !this.$hasPerm('ops.view_adhocexecution')
|
|
||||||
}
|
|
||||||
],
|
|
||||||
hasRightSide: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@@ -1,179 +0,0 @@
|
|||||||
<template>
|
|
||||||
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script type="text/jsx">
|
|
||||||
// import { timeOffset, toSafeLocalDateStr } from '@/utils/common'
|
|
||||||
import { GenericListPage } from '@/layout/components'
|
|
||||||
// import { openTaskPage } from '@/utils/jms'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
GenericListPage
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
tableConfig: {
|
|
||||||
url: '/api/v1/ops/tasks/',
|
|
||||||
columns: [
|
|
||||||
'name', 'queue', 'comment', 'count', 'state', 'last_published_time'
|
|
||||||
],
|
|
||||||
columnsMeta: {
|
|
||||||
name: {
|
|
||||||
formatterArgs: {
|
|
||||||
can: true
|
|
||||||
}
|
|
||||||
// formatter: (row) => {
|
|
||||||
// return row.meta.verbose_name != null ? row.meta.verbose_name : row.name
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
comment: {
|
|
||||||
label: 'comment',
|
|
||||||
formatter: (row) => {
|
|
||||||
return row.meta.comment
|
|
||||||
}
|
|
||||||
},
|
|
||||||
queue: {
|
|
||||||
label: 'queue',
|
|
||||||
formatter: (row) => {
|
|
||||||
return row.meta.queue
|
|
||||||
}
|
|
||||||
},
|
|
||||||
last_published_time: {
|
|
||||||
width: '210px',
|
|
||||||
formatter: (row) => {
|
|
||||||
return row.last_published_time != null ? row.last_published_time : '-'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
count: {
|
|
||||||
label: 'success/total',
|
|
||||||
width: '120px',
|
|
||||||
formatter: (row) => {
|
|
||||||
return <div>
|
|
||||||
<span Class='text-primary'>{row.success_count}</span>/
|
|
||||||
<span>{row.publish_count}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
width: '60px',
|
|
||||||
align: 'center',
|
|
||||||
formatter: (row) => {
|
|
||||||
switch (row.state) {
|
|
||||||
case 'green':
|
|
||||||
return <i Class='fa fa-circle-o text-primary' />
|
|
||||||
case 'yellow':
|
|
||||||
return <i Class='fa fa-circle-o text-warning' />
|
|
||||||
case 'red':
|
|
||||||
return <i Class='fa fa-circle-o text-danger' />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// runtimes: {
|
|
||||||
// label: this.$t('ops.runTimes'),
|
|
||||||
// width: '120px',
|
|
||||||
// formatter: function(row) {
|
|
||||||
// return (<div>
|
|
||||||
// <span Class='text-primary'>{row.summary.success}</span>/
|
|
||||||
// <span Class='text-danger'>{row.summary.failed}</span>/
|
|
||||||
// <span>{row.summary.total}</span>
|
|
||||||
// </div>)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// host_amount: {
|
|
||||||
// label: this.$t('ops.hosts'),
|
|
||||||
// width: '65px',
|
|
||||||
// formatter: function(row) {
|
|
||||||
// return _.get(row, 'latest_execution.hosts_amount', 0)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// is_success: {
|
|
||||||
// label: this.$t('ops.success'),
|
|
||||||
// align: 'center',
|
|
||||||
// width: '80px',
|
|
||||||
// formatter: row => {
|
|
||||||
// if (_.get(row, 'latest_execution.is_success', false)) {
|
|
||||||
// return <i Class='fa fa-check text-primary'/>
|
|
||||||
// }
|
|
||||||
// return <i Class='fa fa-times text-danger'/>
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// date_start: {
|
|
||||||
// label: this.$t('ops.date'),
|
|
||||||
// width: '150px',
|
|
||||||
// formatter: function(row) {
|
|
||||||
// if (_.get(row, 'latest_execution.date_start', false)) {
|
|
||||||
// return toSafeLocalDateStr(row.latest_execution.date_start)
|
|
||||||
// }
|
|
||||||
// return ''
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// time: {
|
|
||||||
// label: this.$t('ops.time'),
|
|
||||||
// width: '100px',
|
|
||||||
// formatter: function(row) {
|
|
||||||
// if (_.get(row, 'latest_execution.date_start', false)) {
|
|
||||||
// return timeOffset(row.latest_execution.date_start, row.latest_execution.date_finished)
|
|
||||||
// }
|
|
||||||
// return ''
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
actions: {
|
|
||||||
prop: 'id',
|
|
||||||
formatterArgs: {
|
|
||||||
// hasUpdate: false,
|
|
||||||
// hasClone: false,
|
|
||||||
// canDelete: this.$hasPerm('ops.delete_task'),
|
|
||||||
// onDelete: function({ row, col, cellValue, reload }) {
|
|
||||||
// const msg = this.$t('common.deleteWarningMsg') + ` "${row.display_name || row.name}" ` + '?'
|
|
||||||
// const title = this.$t('common.Info')
|
|
||||||
// this.$alert(msg, title, {
|
|
||||||
// type: 'warning',
|
|
||||||
// confirmButtonClass: 'el-button--danger',
|
|
||||||
// showCancelButton: true,
|
|
||||||
// beforeClose: async(action, instance, done) => {
|
|
||||||
// if (action !== 'confirm') return done()
|
|
||||||
// instance.confirmButtonLoading = true
|
|
||||||
// try {
|
|
||||||
// await performDelete.bind(this)({ row: row, col: col })
|
|
||||||
// done()
|
|
||||||
// reload()
|
|
||||||
// this.$message.success(this.$t('common.deleteSuccessMsg'))
|
|
||||||
// } finally {
|
|
||||||
// instance.confirmButtonLoading = false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// extraActions: [
|
|
||||||
// {
|
|
||||||
// name: 'run',
|
|
||||||
// can: this.$hasPerm('ops.add_adhoc'),
|
|
||||||
// title: this.$t('ops.run'),
|
|
||||||
// type: 'primary',
|
|
||||||
// callback: function({ row, tableData }) {
|
|
||||||
// this.$axios.get(
|
|
||||||
// `/api/v1/ops/tasks/${row.id}/run/`
|
|
||||||
// ).then(res => {
|
|
||||||
// openTaskPage(res['task'])
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
headerActions: {
|
|
||||||
hasRightActions: false,
|
|
||||||
hasCreate: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@@ -13,7 +13,7 @@
|
|||||||
<script type="text/jsx">
|
<script type="text/jsx">
|
||||||
import DetailCard from '@/components/DetailCard'
|
import DetailCard from '@/components/DetailCard'
|
||||||
import { toSafeLocalDateStr } from '@/utils/common'
|
import { toSafeLocalDateStr } from '@/utils/common'
|
||||||
import RunInfoCard from '../../RunInfoCard'
|
import RunInfoCard from '../../../tasks/RunInfoCard'
|
||||||
import { toLastFailureDisplay, toLastSucessDisplay } from '../business'
|
import { toLastFailureDisplay, toLastSucessDisplay } from '../business'
|
||||||
import { openTaskPage } from '@/utils/jms'
|
import { openTaskPage } from '@/utils/jms'
|
||||||
|
|
@@ -19,7 +19,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tableConfig: {
|
tableConfig: {
|
||||||
url: `/api/v1/ops/tasks/${this.object.id}/executions/`,
|
url: `/api/v1/ops/task-executions/?task_id=${this.object.id}`,
|
||||||
columns: [
|
columns: [
|
||||||
'id', 'state', 'is_finished', 'date_published', 'date_start', 'date_finished', 'actions'
|
'id', 'state', 'is_finished', 'date_published', 'date_start', 'date_finished', 'actions'
|
||||||
],
|
],
|
81
src/views/tasks/TaskList.vue
Normal file
81
src/views/tasks/TaskList.vue
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script type="text/jsx">
|
||||||
|
import { GenericListPage } from '@/layout/components'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
GenericListPage
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tableConfig: {
|
||||||
|
url: '/api/v1/ops/tasks/',
|
||||||
|
columns: [
|
||||||
|
'name', 'queue', 'comment', 'count', 'state', 'last_published_time'
|
||||||
|
],
|
||||||
|
columnsMeta: {
|
||||||
|
name: {
|
||||||
|
formatterArgs: {
|
||||||
|
can: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
label: 'comment',
|
||||||
|
formatter: (row) => {
|
||||||
|
return row.meta.comment
|
||||||
|
}
|
||||||
|
},
|
||||||
|
queue: {
|
||||||
|
label: 'queue',
|
||||||
|
formatter: (row) => {
|
||||||
|
return row.meta.queue
|
||||||
|
}
|
||||||
|
},
|
||||||
|
last_published_time: {
|
||||||
|
width: '210px',
|
||||||
|
formatter: (row) => {
|
||||||
|
return row.last_published_time != null ? row.last_published_time : '-'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
count: {
|
||||||
|
label: 'success/total',
|
||||||
|
width: '120px',
|
||||||
|
formatter: (row) => {
|
||||||
|
return <div>
|
||||||
|
<span Class='text-primary'>{row.success_count}</span>/
|
||||||
|
<span>{row.publish_count}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
width: '60px',
|
||||||
|
align: 'center',
|
||||||
|
formatter: (row) => {
|
||||||
|
switch (row.state) {
|
||||||
|
case 'green':
|
||||||
|
return <i Class='fa fa-circle-o text-primary' />
|
||||||
|
case 'yellow':
|
||||||
|
return <i Class='fa fa-circle-o text-warning' />
|
||||||
|
case 'red':
|
||||||
|
return <i Class='fa fa-circle-o text-danger' />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
headerActions: {
|
||||||
|
hasRightActions: false,
|
||||||
|
hasLeftActions: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
|
||||||
|
</style>
|
Reference in New Issue
Block a user