Browse Source

[Feature][UI Next] Add project task instance. (#8220)

3.0.0/version-upgrade
songjianet 2 years ago committed by GitHub
parent
commit
d1f65053a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      dolphinscheduler-ui-next/package.json
  2. 2518
      dolphinscheduler-ui-next/pnpm-lock.yaml
  3. 32
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  4. 32
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  5. 12
      dolphinscheduler-ui-next/src/service/modules/task-instances/index.ts
  6. 87
      dolphinscheduler-ui-next/src/service/modules/task-instances/types.ts
  7. 82
      dolphinscheduler-ui-next/src/views/projects/task/instance/components/log-modal.tsx
  8. 58
      dolphinscheduler-ui-next/src/views/projects/task/instance/components/use-modal.ts
  9. 26
      dolphinscheduler-ui-next/src/views/projects/task/instance/index.module.scss
  10. 155
      dolphinscheduler-ui-next/src/views/projects/task/instance/index.tsx
  11. 301
      dolphinscheduler-ui-next/src/views/projects/task/instance/use-table.ts
  12. 176
      dolphinscheduler-ui-next/src/views/projects/workflow/relation/index.tsx

2
dolphinscheduler-ui-next/package.json

@ -17,7 +17,7 @@
"echarts": "^5.2.2",
"lodash": "^4.17.21",
"monaco-editor": "^0.31.1",
"naive-ui": "2.23.2",
"naive-ui": "2.24.6",
"nprogress": "^0.2.0",
"pinia": "^2.0.9",
"pinia-plugin-persistedstate": "^1.0.3",

2518
dolphinscheduler-ui-next/pnpm-lock.yaml

File diff suppressed because it is too large Load Diff

32
dolphinscheduler-ui-next/src/locales/modules/en_US.ts

@ -337,6 +337,38 @@ const project = {
workflow_publish_status: 'Workflow Publish Status',
schedule_publish_status: 'Schedule Publish Status'
},
task: {
task_name: 'Task Name',
workflow_instance: 'Workflow Instance',
executor: 'Executor',
node_type: 'Node Type',
state: 'State',
submit_time: 'Submit Time',
start_time: 'Start Time',
end_time: 'End Time',
duration: 'Duration',
retry_count: 'Retry Count',
dry_run_flag: 'Dry Run Flag',
host: 'Host',
operation: 'Operation',
submitted_success: 'Submitted Success',
running_execution: 'Running Execution',
ready_pause: 'Ready Pause',
pause: 'Pause',
ready_stop: 'Ready Stop',
stop: 'Stop',
failure: 'Failure',
success: 'Success',
need_fault_tolerance: 'Need Fault Tolerance',
kill: 'Kill',
waiting_thread: 'Waiting Thread',
waiting_depend: 'Waiting Depend',
delay_execution: 'Delay Execution',
forced_success: 'Forced Success',
serial_wait: 'Serial Wait',
view_log: 'View Log',
download_log: 'Download Log'
},
dag: {
createWorkflow: 'Create Workflow',
search: 'Search',

32
dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts

@ -336,6 +336,38 @@ const project = {
workflow_publish_status: '工作流上线状态',
schedule_publish_status: '定时状态'
},
task: {
task_name: '任务名称',
workflow_instance: '工作流实例',
executor: '执行用户',
node_type: '节点类型',
state: '状态',
submit_time: '提交时间',
start_time: '开始时间',
end_time: '结束时间',
duration: '运行时间',
retry_count: '重试次数',
dry_run_flag: '空跑标识',
host: '主机',
operation: '操作',
submitted_success: '提交成功',
running_execution: '正在运行',
ready_pause: '准备暂停',
pause: '暂停',
ready_stop: '准备停止',
stop: '停止',
failure: '失败',
success: '成功',
need_fault_tolerance: '需要容错',
kill: '已被杀',
waiting_thread: '等待线程',
waiting_depend: '等待依赖完成',
delay_execution: '延时执行',
forced_success: '强制成功',
serial_wait: '串行等待',
view_log: '查看日志',
download_log: '下载日志'
},
dag: {
createWorkflow: '创建工作流',
search: '搜索',

12
dolphinscheduler-ui-next/src/service/modules/task-instances/index.ts

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { axios } from '@/service/service'
import { axios, downloadFile } from '@/service/service'
import { ProjectCodeReq, IdReq, TaskListReq } from './types'
export function queryTaskListPaging(
@ -23,15 +23,19 @@ export function queryTaskListPaging(
projectCode: ProjectCodeReq
): any {
return axios({
url: `/projects/${projectCode}/task-instances`,
url: `/projects/${projectCode.projectCode}/task-instances`,
method: 'get',
params
})
}
export function forceSuccess(id: IdReq, projectCode: ProjectCodeReq): any {
export function forceSuccess(taskId: IdReq, projectCode: ProjectCodeReq): any {
return axios({
url: `/projects/${projectCode}/task-instances/${id}/force-success`,
url: `/projects/${projectCode.projectCode}/task-instances/${taskId.id}/force-success`,
method: 'post'
})
}
export function downloadLog(id: number): void {
downloadFile(`log/download-log`, { taskInstanceId: id })
}

87
dolphinscheduler-ui-next/src/service/modules/task-instances/types.ts

@ -37,4 +37,89 @@ interface TaskListReq {
taskName?: string
}
export { ProjectCodeReq, IdReq, TaskListReq }
interface Dependency {
localParams?: any
varPool?: any
dependTaskList?: any
relation?: any
resourceFilesList: any[]
varPoolMap?: any
localParametersMap?: any
}
interface SwitchDependency extends Dependency {
nextNode?: any
resultConditionLocation: number
dependTaskList?: any
}
interface TotalList {
taskComplete: boolean
firstRun: boolean
environmentCode: number
processInstance?: any
pid: number
appLink: string
taskCode: any
switchTask: boolean
host: string
id: number
state: string
workerGroup: string
conditionsTask: boolean
processInstancePriority?: any
processInstanceId: number
dependency: Dependency
alertFlag: string
dependentResult?: any
executePath: string
switchDependency: SwitchDependency
maxRetryTimes: number
executorName: string
subProcess: boolean
submitTime: string
taskGroupId: number
name: string
taskDefinitionVersion: number
processInstanceName: string
taskGroupPriority: number
taskDefine?: any
dryRun: number
flag: string
taskParams: string
duration: string
processDefine?: any
taskType: string
taskInstancePriority: string
logPath: string
startTime: string
environmentConfig?: any
executorId: number
firstSubmitTime: string
resources?: any
retryTimes: number
varPool: string
dependTask: boolean
delayTime: number
retryInterval: number
endTime: string
}
interface TaskInstancesRes {
totalList: TotalList[]
total: number
totalPage: number
pageSize: number
currentPage: number
start: number
}
export {
ProjectCodeReq,
IdReq,
TaskListReq,
Dependency,
SwitchDependency,
TotalList,
TaskInstancesRes
}

82
dolphinscheduler-ui-next/src/views/projects/task/instance/components/log-modal.tsx

@ -0,0 +1,82 @@
/*
* 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.
*/
import { defineComponent, onMounted, PropType, toRefs, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { NLog } from 'naive-ui'
import { useModal } from './use-modal'
import Modal from '@/components/modal'
const props = {
showModalRef: {
type: Boolean as PropType<boolean>,
default: false
},
row: {
type: Object as PropType<any>,
default: {}
}
}
const LogModal = defineComponent({
name: 'LogModal',
props,
emits: ['confirmModal'],
setup(props, ctx) {
const { t } = useI18n()
const { variables, getLogs } = useModal()
const confirmModal = () => {
ctx.emit('confirmModal', props.showModalRef)
}
watch(
() => props.showModalRef,
() => {
if (props.showModalRef) {
variables.id = props.row.id
props.showModalRef && variables.id && getLogs()
} else {
variables.id = ''
variables.logRef = ''
variables.loadingRef = true
variables.skipLineNum = 0
variables.limit = 1000
}
}
)
return { t, ...toRefs(variables), confirmModal }
},
render() {
const { t } = this
return (
<Modal
title={t('project.task.view_log')}
show={this.showModalRef}
cancelShow={false}
onConfirm={this.confirmModal}
style={{ width: '60%' }}
>
<NLog rows={30} log={this.logRef} loading={this.loadingRef} />
</Modal>
)
}
})
export default LogModal

58
dolphinscheduler-ui-next/src/views/projects/task/instance/components/use-modal.ts

@ -0,0 +1,58 @@
/*
* 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.
*/
import { reactive, ref } from 'vue'
import { useAsyncState } from '@vueuse/core'
import { queryLog } from '@/service/modules/log'
export function useModal() {
const variables = reactive({
id: ref(''),
loadingRef: ref(true),
logRef: ref(''),
skipLineNum: ref(0),
limit: ref(1000)
})
const getLogs = () => {
const { state } = useAsyncState(
queryLog({
taskInstanceId: Number(variables.id),
limit: variables.limit,
skipLineNum: variables.skipLineNum
}).then((res: string) => {
variables.logRef += res
if (res) {
variables.limit += 1000
variables.skipLineNum += 1000
getLogs()
} else {
variables.loadingRef = false
}
}),
{}
)
return state
}
return {
variables,
getLogs
}
}

26
dolphinscheduler-ui-next/src/views/projects/task/instance/index.module.scss

@ -0,0 +1,26 @@
/*
* 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.
*/
.table-card {
margin-top: 8px;
.pagination {
margin-top: 20px;
display: flex;
justify-content: center;
}
}

155
dolphinscheduler-ui-next/src/views/projects/task/instance/index.tsx

@ -15,11 +15,158 @@
* limitations under the License.
*/
import { defineComponent } from 'vue'
import { defineComponent, onMounted, toRefs, watch } from 'vue'
import {
NSpace,
NInput,
NSelect,
NDatePicker,
NButton,
NIcon,
NDataTable,
NPagination,
NCard
} from 'naive-ui'
import { SearchOutlined } from '@vicons/antd'
import { useTable } from './use-table'
import { useI18n } from 'vue-i18n'
import Card from '@/components/card'
import LogModal from './components/log-modal'
import styles from './index.module.scss'
export default defineComponent({
name: 'TaskInstanceList',
const TaskInstance = defineComponent({
name: 'task-instance',
setup() {
return () => <div>TaskInstanceList</div>
const { t, variables, getTableData, createColumns } = useTable()
const requestTableData = () => {
getTableData({
pageSize: variables.pageSize,
pageNo: variables.page,
searchVal: variables.searchVal,
processInstanceId: variables.processInstanceId,
host: variables.host,
stateType: variables.stateType,
datePickerRange: variables.datePickerRange,
executorName: variables.executorName,
processInstanceName: variables.processInstanceName
})
}
const onUpdatePageSize = () => {
variables.page = 1
requestTableData()
}
const onSearch = () => {
variables.page = 1
requestTableData()
}
const onConfirmModal = () => {
variables.showModalRef = false
}
onMounted(() => {
createColumns(variables)
requestTableData()
})
watch(useI18n().locale, () => {
createColumns(variables)
})
return {
t,
...toRefs(variables),
requestTableData,
onUpdatePageSize,
onSearch,
onConfirmModal
}
},
render() {
const { t, requestTableData, onUpdatePageSize, onSearch, onConfirmModal } =
this
return (
<>
<NCard>
<NSpace justify='end'>
<NInput
v-model={[this.searchVal, 'value']}
size='small'
placeholder={t('project.task.task_name')}
clearable
/>
<NInput
v-model={[this.processInstanceName, 'value']}
size='small'
placeholder={t('project.task.workflow_instance')}
clearable
/>
<NInput
v-model={[this.executorName, 'value']}
size='small'
placeholder={t('project.task.executor')}
clearable
/>
<NInput
v-model={[this.host, 'value']}
size='small'
placeholder={t('project.task.host')}
clearable
/>
<NSelect
v-model={[this.stateType, 'value']}
size='small'
options={this.generalOptions}
placeholder={t('project.task.state')}
style={{ width: '180px' }}
clearable
/>
<NDatePicker
v-model={[this.datePickerRange, 'value']}
type='datetimerange'
size='small'
start-placeholder={t('project.task.start_time')}
end-placeholder={t('project.task.end_time')}
clearable
/>
<NButton size='small' type='primary' onClick={onSearch}>
{{
icon: () => (
<NIcon>
<SearchOutlined />
</NIcon>
)
}}
</NButton>
</NSpace>
</NCard>
<Card class={styles['table-card']}>
<NDataTable columns={this.columns} data={this.tableData} />
<div class={styles.pagination}>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={requestTableData}
onUpdatePageSize={onUpdatePageSize}
/>
</div>
</Card>
<LogModal
showModalRef={this.showModalRef}
row={this.row}
onConfirmModal={onConfirmModal}
/>
</>
)
}
})
export default TaskInstance

301
dolphinscheduler-ui-next/src/views/projects/task/instance/use-table.ts

@ -0,0 +1,301 @@
/*
* 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.
*/
import { useI18n } from 'vue-i18n'
import { h, reactive, ref } from 'vue'
import { useAsyncState } from '@vueuse/core'
import {
queryTaskListPaging,
forceSuccess,
downloadLog
} from '@/service/modules/task-instances'
import { NButton, NSpace, NTooltip } from 'naive-ui'
import {
AlignLeftOutlined,
CheckCircleOutlined,
DownloadOutlined
} from '@vicons/antd'
import { format } from 'date-fns'
import { useRoute } from 'vue-router'
import { downloadFile } from '@/service/service'
import type { TaskInstancesRes } from '@/service/modules/task-instances/types'
export function useTable() {
const { t } = useI18n()
const route = useRoute()
const projectCode = Number(route.params.projectCode)
const variables = reactive({
columns: [],
tableData: [],
page: ref(1),
pageSize: ref(10),
searchVal: ref(null),
processInstanceId: ref(null),
host: ref(null),
stateType: ref(null),
datePickerRange: ref(null),
executorName: ref(null),
processInstanceName: ref(null),
totalPage: ref(1),
showModalRef: ref(false),
statusRef: ref(0),
row: {},
generalOptions: [
{
label: t('project.task.submitted_success'),
value: 'SUBMITTED_SUCCESS'
},
{
label: t('project.task.running_execution'),
value: 'RUNNING_EXECUTION'
},
{ label: t('project.task.ready_pause'), value: 'READY_PAUSE' },
{ label: t('project.task.pause'), value: 'PAUSE' },
{ label: t('project.task.ready_stop'), value: 'READY_STOP' },
{ label: t('project.task.stop'), value: 'STOP' },
{ label: t('project.task.failure'), value: 'FAILURE' },
{ label: t('project.task.success'), value: 'SUCCESS' },
{
label: t('project.task.need_fault_tolerance'),
value: 'NEED_FAULT_TOLERANCE'
},
{ label: t('project.task.kill'), value: 'KILL' },
{ label: t('project.task.waiting_thread'), value: 'WAITING_THREAD' },
{ label: t('project.task.waiting_depend'), value: 'WAITING_DEPEND' },
{ label: t('project.task.delay_execution'), value: 'DELAY_EXECUTION' },
{ label: t('project.task.forced_success'), value: 'FORCED_SUCCESS' },
{ label: t('project.task.serial_wait'), value: 'SERIAL_WAIT' }
]
})
const createColumns = (variables: any) => {
variables.columns = [
{
title: '#',
key: 'index'
},
{
title: t('project.task.task_name'),
key: 'name'
},
{
title: t('project.task.workflow_instance'),
key: 'processInstanceName',
width: 250
},
{
title: t('project.task.executor'),
key: 'executorName'
},
{
title: t('project.task.node_type'),
key: 'taskType'
},
{
title: t('project.task.state'),
key: 'state'
},
{
title: t('project.task.submit_time'),
key: 'submitTime',
width: 170
},
{
title: t('project.task.start_time'),
key: 'startTime',
width: 170
},
{
title: t('project.task.end_time'),
key: 'endTime',
width: 170
},
{
title: t('project.task.duration'),
key: 'duration',
render: (row: any) => h('span', null, row.duration ? row.duration : '-')
},
{
title: t('project.task.retry_count'),
key: 'retryTimes'
},
{
title: t('project.task.dry_run_flag'),
key: 'dryRun'
},
{
title: t('project.task.host'),
key: 'host',
width: 160
},
{
title: t('project.task.operation'),
key: 'operation',
width: 150,
render(row: any) {
return h(NSpace, null, {
default: () => [
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'info',
size: 'small',
disabled: !(
row.state === 'FAILURE' ||
row.state === 'NEED_FAULT_TOLERANCE' ||
row.state === 'KILL'
),
onClick: () => {
handleForcedSuccess(row)
}
},
{
icon: () => h(CheckCircleOutlined)
}
),
default: () => t('project.task.serial_wait')
}
),
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'info',
size: 'small',
onClick: () => handleLog(row)
},
{
icon: () => h(AlignLeftOutlined)
}
),
default: () => t('project.task.view_log')
}
),
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'info',
size: 'small',
onClick: () => downloadLog(row.id)
},
{
icon: () => h(DownloadOutlined)
}
),
default: () => t('project.task.download_log')
}
)
]
})
}
}
]
}
const handleLog = (row: any) => {
variables.showModalRef = true
variables.row = row
}
const handleForcedSuccess = (row: any) => {
forceSuccess({ id: row.id }, { projectCode }).then(() => {
getTableData({
pageSize: variables.pageSize,
pageNo:
variables.tableData.length === 1 && variables.page > 1
? variables.page - 1
: variables.page,
searchVal: variables.searchVal,
processInstanceId: variables.processInstanceId,
host: variables.host,
stateType: variables.stateType,
datePickerRange: variables.datePickerRange,
executorName: variables.executorName,
processInstanceName: variables.processInstanceName
})
})
}
const getTableData = (params: any) => {
const data = {
pageSize: params.pageSize,
pageNo: params.pageNo,
searchVal: params.searchVal,
processInstanceId: params.processInstanceId,
host: params.host,
stateType: params.stateType,
startDate: params.datePickerRange
? format(new Date(params.datePickerRange[0]), 'yyyy-MM-dd HH:mm:ss')
: '',
endDate: params.datePickerRange
? format(new Date(params.datePickerRange[1]), 'yyyy-MM-dd HH:mm:ss')
: '',
executorName: params.executorName,
processInstanceName: params.processInstanceName
}
const { state } = useAsyncState(
queryTaskListPaging(data, { projectCode }).then(
(res: TaskInstancesRes) => {
variables.tableData = res.totalList.map((item, index) => {
item.submitTime = format(
new Date(item.submitTime),
'yyyy-MM-dd HH:mm:ss'
)
item.startTime = format(
new Date(item.startTime),
'yyyy-MM-dd HH:mm:ss'
)
item.endTime = format(new Date(item.endTime), 'yyyy-MM-dd HH:mm:ss')
return {
index: index + 1,
...item
}
}) as any
}
),
{}
)
return state
}
return {
t,
variables,
getTableData,
createColumns
}
}

176
dolphinscheduler-ui-next/src/views/projects/workflow/relation/index.tsx

@ -19,104 +19,104 @@ import { defineComponent, onMounted, toRefs, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
import { NSelect, NButton, NIcon, NSpace, NTooltip } from 'naive-ui'
import { ReloadOutlined, EyeOutlined, EditOutlined } from '@vicons/antd'
import { ReloadOutlined, EyeOutlined } from '@vicons/antd'
import { useRelation } from './use-relation'
import Card from '@/components/card'
import Graph from './components/Graph'
const workflowRelation = defineComponent({
name: 'workflow-relation',
setup() {
const { t, locale } = useI18n()
const route = useRoute()
const { variables, getWorkflowName, getOneWorkflow, getWorkflowList } =
useRelation()
name: 'workflow-relation',
setup() {
const { t, locale } = useI18n()
const route = useRoute()
const { variables, getWorkflowName, getOneWorkflow, getWorkflowList } =
useRelation()
onMounted(() => {
getWorkflowList(Number(route.params.projectCode))
getWorkflowName(Number(route.params.projectCode))
})
onMounted(() => {
getWorkflowList(Number(route.params.projectCode))
getWorkflowName(Number(route.params.projectCode))
})
const handleResetDate = () => {
variables.seriesData = []
variables.workflow && variables.workflow !== 0
? getOneWorkflow(
Number(variables.workflow),
Number(route.params.projectCode)
)
: getWorkflowList(Number(route.params.projectCode))
}
const handleResetDate = () => {
variables.seriesData = []
variables.workflow && variables.workflow !== 0
? getOneWorkflow(
Number(variables.workflow),
Number(route.params.projectCode)
)
: getWorkflowList(Number(route.params.projectCode))
}
watch(
() => [variables.workflow, variables.labelShow, locale.value],
() => {
handleResetDate()
}
)
watch(
() => [variables.workflow, variables.labelShow, locale.value],
() => {
handleResetDate()
}
)
return { t, handleResetDate, ...toRefs(variables) }
},
render() {
const { t, handleResetDate } = this
return { t, handleResetDate, ...toRefs(variables) }
},
render() {
const { t, handleResetDate } = this
return (
<Card title={t('project.workflow.workflow_relation')}>
{{
default: () =>
Object.keys(this.seriesData).length > 0 && (
<Graph seriesData={this.seriesData} labelShow={this.labelShow} />
),
'header-extra': () => (
<NSpace>
<NSelect
clearable
style={{ width: '300px' }}
placeholder={t('project.workflow.workflow_name')}
options={this.workflowOptions}
v-model={[this.workflow, 'value']}
/>
<NTooltip trigger={'hover'}>
{{
default: () => t('project.workflow.refresh'),
trigger: () => (
<NButton
strong
secondary
circle
type='info'
onClick={handleResetDate}
>
<NIcon>
<ReloadOutlined />
</NIcon>
</NButton>
)
}}
</NTooltip>
<NTooltip trigger={'hover'}>
{{
default: () => t('project.workflow.show_hide_label'),
trigger: () => (
<NButton
strong
secondary
circle
type='info'
onClick={() => (this.labelShow = !this.labelShow)}
>
<NIcon>
<EyeOutlined />
</NIcon>
</NButton>
)
}}
</NTooltip>
</NSpace>
)
}}
</Card>
)
}
return (
<Card title={t('project.workflow.workflow_relation')}>
{{
default: () =>
Object.keys(this.seriesData).length > 0 && (
<Graph seriesData={this.seriesData} labelShow={this.labelShow} />
),
'header-extra': () => (
<NSpace>
<NSelect
clearable
style={{ width: '300px' }}
placeholder={t('project.workflow.workflow_name')}
options={this.workflowOptions}
v-model={[this.workflow, 'value']}
/>
<NTooltip trigger={'hover'}>
{{
default: () => t('project.workflow.refresh'),
trigger: () => (
<NButton
strong
secondary
circle
type='info'
onClick={handleResetDate}
>
<NIcon>
<ReloadOutlined />
</NIcon>
</NButton>
)
}}
</NTooltip>
<NTooltip trigger={'hover'}>
{{
default: () => t('project.workflow.show_hide_label'),
trigger: () => (
<NButton
strong
secondary
circle
type='info'
onClick={() => (this.labelShow = !this.labelShow)}
>
<NIcon>
<EyeOutlined />
</NIcon>
</NButton>
)
}}
</NTooltip>
</NSpace>
)
}}
</Card>
)
}
})
export default workflowRelation

Loading…
Cancel
Save