Browse Source

[Feature-6600][UI] Implement page about task-definition (#6762)

* fix api error in dependent task

* feat: This is a connecting test

* feat: second push test

* feat: email test

* [Feature]add taskdefinition

add new pages named taskDifinition
add new router
add new action in store/dag

* [Feature] add/edit/view task definition

* [DS-6600][feat][UI] Add page about task-definition list

* Add page about task-definition list
* Add create/edit/view/delete task-definition
* Add research task-definition

This closes #6600

* modify API_BASE

Co-authored-by: wangyizhi <wangyizhi1_yewu@cmss.chinamobile.com>
Co-authored-by: duchao <duchao@cmss.chinamobile.com>
3.0.0/version-upgrade
DuChaoJiaYou 3 years ago committed by GitHub
parent
commit
36c19748a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/_source/referenceFromTask.vue
  2. 93
      dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue
  3. 197
      dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/taskDefinition/_source/list.vue
  4. 307
      dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/taskDefinition/index.vue
  5. 9
      dolphinscheduler-ui/src/js/conf/home/router/index.js
  6. 42
      dolphinscheduler-ui/src/js/conf/home/store/dag/actions.js
  7. 52
      dolphinscheduler-ui/src/js/module/components/conditions/conditions.vue
  8. 6
      dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
  9. 6
      dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
  10. 6
      dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

4
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/_source/referenceFromTask.vue

@ -81,7 +81,7 @@
document.removeEventListener('click', this.outsideClick)
},
methods: {
...mapActions('dag', ['getTaskDefinitions']),
...mapActions('dag', ['getTaskDefinitionList']),
outsideClick (e) {
const elem = this.$refs.copyFrom
if (!elem.contains(e.target) && this.dropdownVisible) {
@ -99,7 +99,7 @@
}
if (this.noMore) return
this.loading = true
this.getTaskDefinitions({
this.getTaskDefinitionsList({
pageNo: this.pageNo,
pageSize: this.pageSize,
searchVal: this.searchVal,

93
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue

@ -46,7 +46,6 @@
</div>
<div class="content-box" v-if="isContentBox">
<div class="form-model">
<!-- Reference from task -->
<!-- <reference-from-task :taskType="nodeData.taskType" /> -->
@ -61,12 +60,34 @@
:disabled="isDetails"
:placeholder="$t('Please enter name (required)')"
maxlength="100"
@blur="_verifName()"
>
</el-input>
</div>
</m-list-box>
<m-list-box v-if="fromTaskDefinition">
<div slot="text">{{ $t("Task Type") }}</div>
<div slot="content">
<el-select
@change="changeTaskType"
:value="nodeData.taskType"
:placeholder="$t('Please select a task type (required)')"
size="small"
style="width: 100%"
:disabled="isDetails"
>
<el-option
v-for="type in tasksTypeList"
:key="type"
:label="type"
:value="type"
:disabled="type === 'CONDITIONS' || type === 'SWITCH'"
>
</el-option>
</el-select>
</div>
</m-list-box>
<!-- Running sign -->
<m-list-box>
<div slot="text">{{ $t("Run flag") }}</div>
@ -358,7 +379,8 @@
@on-params="_onParams"
@on-cache-params="_onCacheParams"
:backfill-item="backfillItem"
ref="PIGEON">
ref="PIGEON"
>
</m-pigeon>
<m-sqoop
v-if="nodeData.taskType === 'SQOOP'"
@ -398,7 +420,7 @@
<!-- Pre-tasks in workflow -->
<m-pre-tasks
ref="preTasks"
v-if="['SHELL', 'SUB_PROCESS'].indexOf(nodeData.taskType) > -1"
v-if="['SHELL', 'SUB_PROCESS'].indexOf(nodeData.taskType) > -1 && !fromTaskDefinition"
:code="code"
/>
</div>
@ -415,7 +437,7 @@
:loading="spinnerLoading"
@click="ok()"
:disabled="isDetails"
>{{ spinnerLoading ? $t("Loading...") : $t("Confirm add") }}
>{{ spinnerLoading ? $t("Loading...") : $t("Confirm") }}
</el-button>
</div>
</div>
@ -453,6 +475,7 @@
import disabledState from '@/module/mixin/disabledState'
import mPriority from '@/module/components/priority/priority'
import { findComponentDownward } from '@/module/util/'
import { tasksType } from '@/conf/home/pages/dag/_source/config.js'
// import ReferenceFromTask from './_source/referenceFromTask.vue'
export default {
@ -524,7 +547,8 @@
// refresh part of the formModel, after set backfillItem outside
backfillRefresh: true,
// whether this is a new Task
isNewCreate: true
isNewCreate: true,
tasksTypeList: Object.keys(tasksType)
}
},
provide () {
@ -542,7 +566,8 @@
type: {
type: String,
default: ''
}
},
taskDefinition: Object
},
inject: ['dagChart'],
methods: {
@ -723,6 +748,16 @@
}
return true
},
_verifTaskType () {
if (!this.fromTaskDefinition) return true
if (!this.nodeData.taskType) {
this.$message.warning(
`${i18n.$t('Please select a task type (required)')}`
)
return false
}
return true
},
/**
* Global verification procedure
*/
@ -731,6 +766,12 @@
if (!this._verifName()) {
return
}
// Verify task type
if (!this._verifTaskType()) {
return
}
// verif workGroup
if (!this._verifWorkGroup()) {
return
@ -777,14 +818,11 @@
timeoutNotifyStrategy: this.timeout.strategy,
timeout: this.timeout.interval || 0,
delayTime: this.delayTime,
environmentCode: this.environmentCode || -1,
status: this.status,
branch: this.branch
environmentCode: this.environmentCode || -1
},
fromThis: this
})
// set run flag
this._setRunFlag()
// set edge label
this._setEdgeLabel()
},
@ -795,10 +833,8 @@
this.name = name
},
/**
* set run flag
* TODO
* set edge label by successBranch && failedBranch
*/
_setRunFlag () {},
_setEdgeLabel () {
if (this.successBranch || this.failedBranch) {
const canvas = findComponentDownward(this.dagChart, 'dag-canvas')
@ -892,7 +928,8 @@
} else {
this.workerGroup = o.workerGroup
}
this.environmentCode = o.environmentCode === -1 ? '' : o.environmentCode
this.environmentCode =
o.environmentCode === -1 ? '' : o.environmentCode
this.params = o.params || {}
this.dependence = o.dependence || {}
this.cacheDependence = o.dependence || {}
@ -901,12 +938,25 @@
}
this.cacheBackfillItem = JSON.parse(JSON.stringify(o))
this.isContentBox = true
},
changeTaskType (value) {
this.$emit('changeTaskType', value)
}
},
created () {
// Backfill data
let taskList = this.store.state.dag.tasks
let o = {}
this.code = this.nodeData.id
if (this.fromTaskDefinition) {
if (this.taskDefinition) {
const backfillItem = this.taskToBackfillItem(this.taskDefinition)
o = backfillItem
this.backfillItem = backfillItem
this.isNewCreate = false
}
} else {
let taskList = this.store.state.dag.tasks
if (taskList.length) {
taskList.forEach((task) => {
if (task.code === this.nodeData.id) {
@ -917,7 +967,8 @@
}
})
}
this.code = this.nodeData.id
}
this.backfill(o)
if (this.dagChart) {
@ -958,6 +1009,12 @@
)
}
return null
},
/**
* Open the modal from task definition
*/
fromTaskDefinition () {
return this.type === 'task-definition'
}
},
components: {

197
dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/taskDefinition/_source/list.vue

@ -0,0 +1,197 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
<template>
<div class="list-model" style="position: relative">
<div class="table-box">
<el-table
:data="list"
size="mini"
style="width: 100%"
@selection-change="select"
>
<el-table-column
prop="id"
:label="$t('#')"
min-width="50"
></el-table-column>
<el-table-column :label="$t('Task Name')" min-width="200">
<template v-slot="scope">
<el-popover trigger="hover" placement="top">
<p>{{ scope.row.name }}</p>
<div slot="reference" class="name-wrapper">
<a
href="javascript:"
class="links"
@click="viewTaskDetail(scope.row)"
>
{{ scope.row.name }}
</a>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column :label="$t('Task Type')" prop="taskType" min-width="135">
</el-table-column>
<el-table-column
:label="$t('User Name')"
prop="userName"
width="135"
></el-table-column>
<el-table-column :label="$t('Version Info')" min-width="135">
<template v-slot="scope">
<span>
{{ 'V' + scope.row.version }}
</span>
</template>
</el-table-column>
<el-table-column :label="$t('Create Time')" min-width="135">
<template v-slot="scope">
<span>
{{ scope.row.createTime | formatDate }}
</span>
</template>
</el-table-column>
<el-table-column :label="$t('Update Time')" min-width="135">
<template v-slot="scope">
<span>
{{ scope.row.updateTime | formateDate }}
</span>
</template>
</el-table-column>
<el-table-column :label="$t('Description')" min-width="100">
<template v-slot="scope">
<span>{{ scope.row.description | filterNull }} </span>
</template>
</el-table-column>
<el-table-column :label="$t('Operation')" width="100" fixed="right">
<template v-slot="scope">
<el-tooltip
:content="$t('Edit')"
placement="top"
:enterable="false"
>
<span>
<el-button
type="primary"
size="mini"
icon="el-icon-edit-outline"
circle
:disabled="scope.row.taskType === 'CONDITIONS' || scope.row.taskType ==='SWITCH' "
@click="editTask(scope.row)"
></el-button>
</span>
</el-tooltip>
<el-tooltip
:content="$t('Delete')"
placement="top"
:enterable="false"
>
<el-popconfirm
:confirmButtonText="$t('Confirm')"
:cancelButtonText="$t('Cancel')"
icon="el-icon-info"
iconColor="red"
:title="$t('Delete?')"
@onConfirm="deleteTask(scope.row.code, scope.row.projectCode)"
>
<el-button
type="danger"
size="mini"
icon="el-icon-delete"
slot="reference"
circle
>
</el-button>
</el-popconfirm>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import { mapActions } from 'vuex'
export default {
name: 'task-list',
data () {
return {
list: []
}
},
props: {
tasksList: Array
},
watch: {
tasksList: {
handler (a) {
this.list = []
setTimeout(() => {
this.list = _.cloneDeep(a)
})
},
immediate: true,
deep: true
}
},
created () {
// this.list = this.tasksList
},
methods: {
...mapActions('dag', ['deleteTaskDefinition']),
/**
* onUpdate
*/
_onUpdate () {
this.$emit('on-update')
},
/**
* deleteTaskDefinition
*/
deleteTask (code) {
this.deleteTaskDefinition({
code: code
})
.then((res) => {
this._onUpdate()
this.$message.success(res.msg)
})
.catch((e) => {
this.$message.error(e.msg || '')
})
},
/**
* taskdefinition detail
*/
viewTaskDetail (task) {
this.$emit('viewTaskDetail', task)
},
/**
* task edit
*/
editTask (task) {
this.$emit('editTask', task)
}
}
}
</script>
<style>
</style>

307
dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/taskDefinition/index.vue

@ -0,0 +1,307 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
<template>
<div class="task-definition" v-if="!isLoading">
<m-list-construction :title="$t('Task Definition')">
<template slot="conditions">
<m-conditions @on-conditions="_onConditions" :taskTypeShow="true">
<template v-slot:button-group>
<el-button size="mini" @click="createTask">
{{ $t("Create task") }}
</el-button>
</template>
</m-conditions>
</template>
<template v-slot:content>
<template v-if="tasksList.length || total > 0">
<m-list
:tasksList="tasksList"
@on-update="_onUpdate"
@editTask="editTask"
@viewTaskDetail="viewTaskDetail"
></m-list>
<div class="page-box">
<el-pagination
background
@current-change="_page"
@size-change="_pageSize"
:page-size="searchParams.pageSize"
:current-page.sync="searchParams.pageNo"
:page-sizes="[10, 30, 50]"
:total="total"
layout="sizes, prev, pager, next, jumper"
>
</el-pagination>
</div>
</template>
<template v-if="!tasksList.length">
<m-no-data></m-no-data>
</template>
<m-spin :is-spin="isLoading"></m-spin>
</template>
</m-list-construction>
<el-drawer
:visible.sync="taskDrawer"
size=""
:with-header="false"
@close="closeTaskDrawer"
>
<!-- fix the bug that Element-ui(2.13.2) auto focus on the first input -->
<div style="width: 0px; height: 0px; overflow: hidden">
<el-input type="text" />
</div>
<m-form-model
v-if="taskDrawer"
:nodeData="nodeData"
type="task-definition"
@changeTaskType="changeTaskType"
@close="closeTaskDrawer"
@addTaskInfo="saveTask"
:taskDefinition="editingTask"
>
</m-form-model>
</el-drawer>
</div>
</template>
<script>
import mListConstruction from '@/module/components/listConstruction/listConstruction'
import mConditions from '@/module/components/conditions/conditions'
import mList from './_source/list'
import mNoData from '@/module/components/noData/noData'
import mSpin from '@/module/components/spin/spin'
import { mapActions, mapMutations } from 'vuex'
import listUrlParamHandle from '@/module/mixin/listUrlParamHandle'
import mFormModel from '@/conf/home/pages/dag/_source/formModel/formModel.vue'
/**
* tasksType
*/
import { tasksType } from '@/conf/home/pages/dag/_source/config.js'
const DEFAULT_NODE_DATA = {
id: -1,
taskType: 'SHELL',
instanceId: -1
}
export default {
name: 'task-definition-index',
data () {
// tasksType
const tasksTypeList = Object.keys(tasksType)
return {
total: null,
tasksList: [],
isLoading: true,
searchParams: {
pageSize: 10,
pageNo: 1,
searchVal: '',
taskType: '',
userId: ''
},
// whether the task config drawer is visible
taskDrawer: false,
// nodeData
nodeData: { ...DEFAULT_NODE_DATA },
// tasksType
tasksTypeList,
// editing task definition
editingTask: null
}
},
mixins: [listUrlParamHandle],
methods: {
...mapActions('dag', [
'getTaskDefinitionsList',
'genTaskCodeList',
'saveTaskDefinition',
'updateTaskDefinition'
]),
...mapActions('dag', [
'getProcessList',
'getProjectList',
'getResourcesList',
'getResourcesListJar',
'getResourcesListJar'
]),
...mapMutations('dag', ['resetParams', 'setIsDetails']),
...mapActions('security', [
'getTenantList',
'getWorkerGroupsAll',
'getAlarmGroupsAll'
]),
/**
* Toggle task drawer
*/
showTaskDrawer () {
this.taskDrawer = true
},
closeTaskDrawer () {
this.setIsDetails(false)
this.taskDrawer = false
},
saveTask ({ item }) {
const isEditing = !!this.editingTask
if (isEditing) {
this.updateTaskDefinition(item)
.then((res) => {
this.$message.success(res.msg)
this._onUpdate()
this.closeTaskDrawer()
})
.catch((e) => {
this.$message.error(e.msg || '')
})
} else {
this.genTaskCodeList({
genNum: 1
})
.then((res) => {
const [code] = res
return code
})
.then((code) => {
return this.saveTaskDefinition({
taskDefinitionJson: [
{
...item,
code
}
]
})
})
.then((res) => {
this.$message.success(res.msg)
this._onUpdate()
this.closeTaskDrawer()
})
.catch((e) => {
this.$message.error(e.msg || '')
})
}
},
createTask () {
this.editingTask = null
this.nodeData.taskType = DEFAULT_NODE_DATA.taskType
this.showTaskDrawer()
},
editTask (task) {
this.editingTask = task
this.nodeData.id = task.code
this.nodeData.taskType = task.taskType
this.showTaskDrawer()
},
viewTaskDetail (task) {
this.setIsDetails(true)
this.editTask(task)
},
/**
* pageNo
*/
_page (val) {
this.searchParams.pageNo = val
},
_pageSize (val) {
this.searchParams.pageSize = val
},
/**
* conditions
*/
_onConditions (o) {
this.searchParams.searchVal = o.searchVal
this.searchParams.taskType = o.taskType
this.searchParams.pageNo = 1
},
/**
* get task definition list
*/
_getList (flag) {
this.isLoading = !flag
this.getTaskDefinitionsList(this.searchParams)
.then((res) => {
if (this.searchParams.pageNo > 1 && res.totalList.length === 0) {
this.searchParams.pageNo = this.searchParams.pageNo - 1
} else {
this.tasksList = []
this.tasksList = res.totalList
this.total = res.total
this.isLoading = false
}
})
.catch((e) => {
this.isLoading = false
})
},
/**
* update task dataList
*/
_onUpdate () {
this._debounceGET('false')
},
/**
* change form modal task type
*/
changeTaskType (value) {
this.nodeData.taskType = value
}
},
created () {
this.isLoading = true
// Initialization parameters
this.resetParams()
// Promise Get node needs data
Promise.all([
// get process definition
this.getProcessList(),
// get project
this.getProjectList(),
// get jar
this.getResourcesListJar(),
// get resource
this.getResourcesList(),
// get jar
this.getResourcesListJar(),
// get worker group list
this.getWorkerGroupsAll(),
// get alarm group list
this.getAlarmGroupsAll(),
this.getTenantList()
])
.then((data) => {
this.isLoading = false
})
.catch(() => {
this.isLoading = false
})
},
mounted () {},
components: {
mListConstruction,
mConditions,
mList,
mNoData,
mSpin,
mFormModel
}
}
</script>
<style lang="scss" scoped>
.task-definition {
.taskGroupBtn {
width: 300px;
}
}
</style>

9
dolphinscheduler-ui/src/js/conf/home/router/index.js

@ -207,6 +207,15 @@ const router = new Router({
}
},
{
path: '/projects/:projectCode/task-definition',
name: 'task-definition',
component: resolve => require(['../pages/projects/pages/taskDefinition/index'], resolve),
meta: {
title: `${i18n.$t('Task Definition')}`,
refreshInSwitchedTab: config.refreshInSwitchedTab
}
},
{
path: '/projects/:projectCode/task-record',
name: 'task-record',

42
dolphinscheduler-ui/src/js/conf/home/store/dag/actions.js

@ -836,7 +836,10 @@ export default {
})
})
},
getTaskDefinitions ({ state }, payload) {
/**
* Query Task Definitions List Paging
*/
getTaskDefinitionsList ({ state }, payload) {
return new Promise((resolve, reject) => {
io.get(`projects/${state.projectCode}/task-definition`, payload, res => {
resolve(res.data)
@ -844,5 +847,42 @@ export default {
reject(e)
})
})
},
/**
* Delete Task Definition by code
*/
deleteTaskDefinition ({ state }, payload) {
return new Promise((resolve, reject) => {
io.delete(`projects/${state.projectCode}/task-definition/${payload.code}`, payload, res => {
resolve(res)
}).catch(e => {
reject(e)
})
})
},
/**
* Save Task Definition
*/
saveTaskDefinition ({ state }, payload) {
return new Promise((resolve, reject) => {
io.post(`projects/${state.projectCode}/task-definition`, {
taskDefinitionJson: JSON.stringify(payload.taskDefinitionJson)
}, res => {
resolve(res)
}).catch(e => {
reject(e)
})
})
},
updateTaskDefinition ({ state }, taskDefinition) {
return new Promise((resolve, reject) => {
io.put(`projects/${state.projectCode}/task-definition/${taskDefinition.code}`, {
taskDefinitionJsonObj: JSON.stringify(taskDefinition)
}, res => {
resolve(res)
}).catch(e => {
reject(e)
})
})
}
}

52
dolphinscheduler-ui/src/js/module/components/conditions/conditions.vue

@ -24,17 +24,42 @@
<slot name="search-group" v-if="isShow"></slot>
<template v-if="!isShow">
<div class="list">
<el-button size="mini" @click="_ckQuery" icon="el-icon-search"></el-button>
<el-button
size="mini"
@click="_ckQuery"
icon="el-icon-search"
></el-button>
</div>
<div class="list">
<el-input v-model="searchVal"
<el-input
v-model="searchVal"
@keyup.enter="_ckQuery"
size="mini"
:placeholder="$t('Please enter keyword')"
type="text"
style="width:180px;">
style="width: 180px"
clearable
>
</el-input>
</div>
<div class="list" v-if="taskTypeShow">
<el-select
size="mini"
style="width: 140px"
:placeholder="$t('type')"
:value="taskType"
@change="_onChangeTaskType"
clearable
>
<el-option
v-for="(task, index) in taskTypeList"
:key="index"
:value="task.desc"
:label="index"
>
</el-option>
</el-select>
</div>
</template>
</div>
</div>
@ -42,24 +67,40 @@
</template>
<script>
import _ from 'lodash'
/**
* taskType list
*/
import { tasksType } from '@/conf/home/pages/dag/_source/config.js'
export default {
name: 'conditions',
data () {
return {
// taskType list
taskTypeList: tasksType,
// search value
searchVal: ''
searchVal: '',
// taskType switch
taskType: ''
}
},
props: {
taskTypeShow: Boolean,
operation: Array
},
methods: {
/**
* switch taskType
*/
_onChangeTaskType (val) {
this.taskType = val
},
/**
* emit Query parameter
*/
_ckQuery () {
this.$emit('on-conditions', {
searchVal: _.trim(this.searchVal)
searchVal: _.trim(this.searchVal),
taskType: this.taskType
})
}
},
@ -73,6 +114,7 @@
// Routing parameter merging
if (!_.isEmpty(this.$route.query)) {
this.searchVal = this.$route.query.searchVal || ''
this.taskType = this.$route.query.taskType || ''
}
},
components: {}

6
dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js

@ -76,6 +76,12 @@ const menu = {
path: 'history-task-record',
id: 4,
enabled: config.recordSwitch
},
{
name: `${i18n.$t('Task Definition')}`,
path: 'task-definition',
id: 5,
enabled: true
}
]
}

6
dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js

@ -711,6 +711,9 @@ export default {
'The condition content cannot be empty': 'The condition content cannot be empty',
'Reference from': 'Reference from',
'No more...': 'No more...',
'Task Definition': 'Task Definition',
'Create task': 'Create task',
'Task Type': 'Task Type',
'Process execute type': 'Process execute type',
parallel: 'parallel',
'Serial wait': 'Serial wait',
@ -744,5 +747,6 @@ export default {
agentId: 'AgentId',
users: 'Users',
Username: 'Username',
showType: 'Show Type'
showType: 'Show Type',
'Please select a task type (required)': 'Please select a task type (required)'
}

6
dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

@ -711,6 +711,9 @@ export default {
'The condition content cannot be empty': '条件内容不能为空',
'Reference from': '使用已有任务',
'No more...': '没有更多了...',
'Task Definition': '任务定义',
'Create task': '创建任务',
'Task Type': '任务类型',
'Process execute type': '执行策略',
parallel: '并行',
'Serial wait': '串行等待',
@ -745,5 +748,6 @@ export default {
agentId: '应用ID',
users: '群员',
Username: '用户名',
showType: '内容展示类型'
showType: '内容展示类型',
'Please select a task type (required)': '请选择任务类型(必选)'
}

Loading…
Cancel
Save