feat: Job 支持运行参数

This commit is contained in:
Aaron3S 2022-11-17 20:11:00 +08:00
parent 95945a3b20
commit 4b84a77a5a
9 changed files with 383 additions and 21 deletions

View File

@ -5,9 +5,11 @@
style="height: 100%;width: 100%;vertical-align: middle;display: inline-block;background-color: #1ab394"
>
<template v-for="(item,index) in toolbar">
<el-button v-if="item.type==='button'" :key="index" size="mini">
<i :class="item.icon" />
</el-button>
<el-tooltip :key="index" :content="item.tip" placement="top">
<el-button v-if="item.type==='button'" size="mini" type="primary" @click="item.callback">
<i :class="item.icon" />
</el-button>
</el-tooltip>
</template>
</div>
<codemirror ref="myCm" v-model="iValue" :options="cmOptions" />
@ -64,6 +66,7 @@ export default {
return this.value
},
set(val) {
this.$emit('update:value', val)
this.$emit('change', val)
}
}

View File

@ -701,7 +701,9 @@
"Module": "模块",
"Asset": "资产",
"Plan": "计划",
"AssetAmount": "资产数量"
"AssetAmount": "资产数量",
"SelectAdhoc": "选择命令",
"SaveAdhoc": "保存命令"
},
"perms": {
"": "",

View File

@ -12,13 +12,6 @@ export default {
},
data() {
return {
cmOptions: {
tabSize: 4,
mode: 'shell',
theme: 'base16-light',
lineNumbers: true,
line: true
},
url: '/api/v1/ops/adhocs/',
fields: [
[this.$t('common.Basic'), ['name', 'module', 'args']]

View File

@ -0,0 +1,86 @@
<template>
<GenericListTableDialog
:header-actions="headerActions"
:visible.sync="iVisible"
v-bind="config"
/>
</template>
<script>
import { GenericListTableDialog } from '@/layout/components'
import { ActionsFormatter } from '@/components/TableFormatters'
export default {
components: {
GenericListTableDialog
},
props: {
account: {
type: Object,
default: () => ({})
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
config: {
title: this.$t('ops.SelectAdhoc'),
visible: false,
width: '60%',
tableConfig: {
url: `/api/v1/ops/adhocs/`,
columns: ['name', 'module', 'args', 'actions'],
columnsMeta: {
actions: {
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false,
hasClone: false,
hasDelete: false,
extraActions: [
{
title: '选择',
name: 'select',
can: true,
callback: ({ row }) => {
this.$emit('select', row)
this.iVisible = false
}
}
]
}
}
}
}
},
headerActions: {
hasImport: false,
hasExport: false,
hasLeftActions: false,
hasColumnSetting: false,
hasSearch: false,
searchConfig: {
getUrlQuery: false
}
}
}
},
computed: {
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,79 @@
<template>
<Dialog
v-if="iVisible"
:title="$tc('ops.SaveAdhoc')"
:visible.sync="iVisible"
width="40%"
top="1vh"
:show-cancel="false"
:show-confirm="false"
>
<GenericCreateUpdateForm v-if="ready" v-bind="$data" />
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog'
import { GenericCreateUpdateForm } from '@/layout/components'
import CodeEditor from '@/components/FormFields/CodeEditor'
export default {
components: {
Dialog, GenericCreateUpdateForm
},
props: {
visible: {
type: Boolean,
default: false
},
args: {
type: String,
default: () => ({})
}
},
data() {
return {
ready: false,
url: '/api/v1/ops/adhocs/',
fields: [
['', ['name', 'module', 'args']]
],
initial: {
module: 'shell',
args: ''
},
fieldsMeta: {
args: {
label: 'content',
component: CodeEditor
}
}
}
},
computed: {
iVisible: {
set(val) {
this.$emit('update:visible', val)
},
get() {
return this.visible
}
}
}, mounted() {
this.initial.args = this.args
this.ready = true
}
}
</script>
<style lang="scss" scoped>
.el-row-divider {
margin-bottom: 20px;
}
.select-prop-label {
float: right;
padding-right: 30px;
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<div>
<AdhocOpenDialog v-if="showOpenAdhocDialog" :visible.sync="showOpenAdhocDialog" @select="onSelectAdhoc" />
<AdhocSaveDialog
v-if="showOpenAdhocSaveDialog"
:args="iValue"
:visible.sync="showOpenAdhocSaveDialog"
/>
<CodeEditor :value.sync="iValue" :toolbar="toolbar" />
</div>
</template>
<script>
import CodeEditor from '@/components/FormFields/CodeEditor'
import AdhocOpenDialog from '@/views/ops/Job/AdhocOpenDialog'
import AdhocSaveDialog from '@/views/ops/Job/AdhocSaveDialog'
export default {
components: {
CodeEditor,
AdhocOpenDialog,
AdhocSaveDialog
},
props: {
value: {
type: [String, Object],
default: () => ''
}
},
data() {
return {
showOpenAdhocDialog: false,
showOpenAdhocSaveDialog: false,
toolbar: [
{
type: 'button',
icon: 'fa fa-folder-open-o',
tip: 'Open Command',
callback: () => {
this.openAdhocSelectDialog()
}
},
{
type: 'button',
icon: 'fa fa-save',
tip: 'Save Command',
callback: () => {
this.openAdhocSaveDialog()
}
}
]
}
},
computed: {
iValue: {
get() {
return this.value
},
set(val) {
this.$emit('change', val)
}
}
}, methods: {
openAdhocSelectDialog() {
this.showOpenAdhocDialog = true
},
openAdhocSaveDialog() {
this.showOpenAdhocSaveDialog = true
},
onSelectAdhoc(adhoc) {
this.iValue = adhoc.args
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,92 @@
<template>
<Dialog
v-if="iVisible"
:title="$tc('ops.SaveAdhoc')"
:visible.sync="iVisible"
width="50%"
top="1vh"
:show-cancel="false"
:show-confirm="false"
>
<el-form ref="form" :model="form" label-width="140px">
<el-form-item v-for="(item,key,index) in vars" :key="index" :label="item.label">
<template v-if="item.type === 'select'">
<el-select v-model="form[key]">
<el-option
v-for="option in item.options"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</template>
<template v-else>
<el-input v-model="form[key]" />
</template>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">执行</el-button>
</el-form-item>
</el-form>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog'
export default {
components: {
Dialog
},
props: {
visible: {
type: Boolean,
default: false
},
item: {
type: Object,
default: () => ({})
}
},
data() {
return {
vars: {},
form: {}
}
},
computed: {
iVisible: {
set(val) {
this.$emit('update:visible', val)
},
get() {
return this.visible
}
}
},
mounted() {
this.vars = JSON.parse(this.item.parameters_define)
for (const key of Object.keys(this.vars)) {
this.form[key] = this.vars[key].default || ''
}
},
methods: {
onSubmit() {
this.$emit('submit', this.item, JSON.stringify(this.form))
this.iVisible = false
}
}
}
</script>
<style lang="scss" scoped>
.el-row-divider {
margin-bottom: 20px;
}
.select-prop-label {
float: right;
padding-right: 30px;
}
</style>

View File

@ -1,14 +1,14 @@
<template>
<div v-if="ready">
<GenericCreateUpdatePage v-bind="$data" />
<GenericCreateUpdatePage ref="form" v-bind="$data" />
</div>
</template>
<script>
import { GenericCreateUpdatePage } from '@/layout/components'
import CodeEditor from '@/components/FormFields/CodeEditor'
import AssetSelect from '@/components/AssetSelect'
import { JsonEditor } from '@/components/FormFields'
import JobCodeEditor from '@/views/ops/Job/JobCodeEditor'
export default {
components: {
@ -17,6 +17,7 @@ export default {
data() {
return {
ready: false,
showOpenAdhocDialog: false,
instantTask: false,
jobType: '',
url: '/api/v1/ops/jobs/',
@ -24,7 +25,7 @@ export default {
[this.$t('common.Basic'), ['name', 'type', 'instant', 'comment']],
[this.$t('common.Task'), ['module', 'args', 'playbook', 'chdir', 'timeout']],
[this.$t('ops.Asset'), ['assets', 'runas', 'runas_policy']],
[this.$t('ops.Variable'), ['variables']],
[this.$t('ops.Variable'), ['parameters_define']],
[this.$t('ops.Plan'), ['runAfterSave', 'periodic', 'crontab']]
],
initial: {
@ -34,7 +35,7 @@ export default {
runas_policy: 'skip',
runAfterSave: false,
instant: false,
variables: '{}',
parameters_define: '{}',
timeout: 60,
periodic: false,
crontab: '0 0 * * *'
@ -81,14 +82,14 @@ export default {
hidden: (formValue) => {
return formValue.type !== 'adhoc'
},
component: CodeEditor
component: JobCodeEditor
},
instant: {
hidden: () => {
return true
}
},
variables: {
parameters_define: {
label: this.$t('ops.Variable'),
component: JsonEditor
},
@ -139,6 +140,16 @@ export default {
} else {
this.ready = true
}
},
methods: {
openAdhocSelectDialog() {
this.showOpenAdhocDialog = true
},
onSelectAdhoc(item) {
},
onOpenSaveAdhocDialog() {
}
}
}

View File

@ -1,18 +1,26 @@
<template>
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
<div>
<JobRunDialog v-if="showJobRunDialog" :visible.sync="showJobRunDialog" :item="item" @submit="runJob" />
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
</div>
</template>
<script>
import GenericListPage from '@/layout/components/GenericListPage'
import { ActionsFormatter } from '@/components/TableFormatters'
import { openTaskPage } from '@/utils/jms'
import JobRunDialog from '@/views/ops/Job/JobRunDialog'
export default {
components: {
JobRunDialog,
GenericListPage
},
data() {
return {
item: {},
runtime_parameters: {},
showJobRunDialog: false,
tableConfig: {
url: '/api/v1/ops/jobs/',
columns: [
@ -46,7 +54,12 @@ export default {
type: 'running',
can: true,
callback: ({ row }) => {
this.runJob(row)
if (row.parameters_define) {
this.item = row
this.showJobRunDialog = true
} else {
this.runJob(row)
}
}
}
]
@ -65,8 +78,12 @@ export default {
}
},
methods: {
runJob(row) {
this.$axios.post('/api/v1/ops/job-executions/', { job: row.id }).then(data => {
runJob(row, parameters) {
console.log(row)
this.$axios.post('/api/v1/ops/job-executions/', {
job: row.id,
parameters: parameters
}).then(data => {
this.$axios.get(`/api/v1/ops/job-executions/${data.id}/`).then(d => {
openTaskPage(d.task_id)
})