From ddf90c4d951b06f483151e8e537f6ec9db9d7bf3 Mon Sep 17 00:00:00 2001 From: calvin Date: Fri, 25 Feb 2022 15:05:24 +0800 Subject: [PATCH] [Feature][UI Next] Add the form of the switch task to the module of next ui. (#8536) * add the form of the switch task * add the component of the switch task * developed the form of the switch task * developed the form of the switch task --- .../src/components/form/fields/index.ts | 1 + .../components/form/fields/multi-condition.ts | 153 ++++++++++++++++++ .../src/components/form/types.ts | 1 + .../src/locales/modules/en_US.ts | 4 +- .../src/locales/modules/zh_CN.ts | 4 +- .../task/components/node/fields/index.ts | 1 + .../task/components/node/fields/use-switch.ts | 107 ++++++++++++ .../task/components/node/format-data.ts | 14 ++ .../task/components/node/tasks/use-switch.ts | 85 ++++++++++ .../projects/task/components/node/types.ts | 13 ++ .../projects/task/components/node/use-task.ts | 10 ++ .../components/dag/status.module.scss | 2 +- 12 files changed, 392 insertions(+), 3 deletions(-) create mode 100644 dolphinscheduler-ui-next/src/components/form/fields/multi-condition.ts create mode 100644 dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-switch.ts create mode 100644 dolphinscheduler-ui-next/src/views/projects/task/components/node/tasks/use-switch.ts diff --git a/dolphinscheduler-ui-next/src/components/form/fields/index.ts b/dolphinscheduler-ui-next/src/components/form/fields/index.ts index abf42209f8..800514ab72 100644 --- a/dolphinscheduler-ui-next/src/components/form/fields/index.ts +++ b/dolphinscheduler-ui-next/src/components/form/fields/index.ts @@ -25,3 +25,4 @@ export { renderSelect } from './select' export { renderCheckbox } from './checkbox' export { renderTreeSelect } from './tree-select' export { renderMultiInput } from './multi-input' +export { renderMultiCondition } from './multi-condition' diff --git a/dolphinscheduler-ui-next/src/components/form/fields/multi-condition.ts b/dolphinscheduler-ui-next/src/components/form/fields/multi-condition.ts new file mode 100644 index 0000000000..c091eebdd9 --- /dev/null +++ b/dolphinscheduler-ui-next/src/components/form/fields/multi-condition.ts @@ -0,0 +1,153 @@ +/* + * 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, h, unref, renderSlot } from 'vue' +import { useFormItem } from 'naive-ui/es/_mixins' +import { + NFormItemGi, + NSpace, + NButton, + NGrid, + NGridItem, + NInput, + NSelect +} from 'naive-ui' +import { PlusOutlined, DeleteOutlined } from '@vicons/antd' +import type { IJsonItem, FormItemRule } from '../types' +import getField from '@/components/form/fields/get-field' +import { formatValidate } from '@/components/form/utils' + +const MultiCondition = defineComponent({ + name: 'MultiCondition', + emits: ['add'], + setup(props, ctx) { + const formItem = useFormItem({}) + const onAdd = () => void ctx.emit('add') + + return { onAdd, disabled: formItem.mergedDisabledRef } + }, + render() { + const { disabled, $slots, onAdd } = this + + return h( + NSpace, + { vertical: true, style: { width: '100%' } }, + { + default: () => { + return [ + renderSlot($slots, 'default', { disabled }), + h( + NButton, + { + circle: true, + size: 'tiny', + type: 'info', + disabled, + onClick: onAdd + }, + { + icon: () => h(PlusOutlined) + } + ) + ] + } + } + ) + } +}) + +export function renderMultiCondition( + item: IJsonItem, + fields: { [field: string]: any }, + rules: { [key: string]: FormItemRule }[] +) { + let ruleItem: { [key: string]: FormItemRule } = {} + + // the fields is the data of the task definition. + // the item is the options of this component in the form. + const { field, children = [] } = item + + children.forEach((child: IJsonItem) => { + if (child.validate) { + ruleItem[child.field] = formatValidate(child.validate) + } + }) + + const getChild = (item: object, i: number) => + children.map((child: IJsonItem) => { + return h( + NFormItemGi, + { + showLabel: child.name ? true : false, + label: child.name ? child.name : '', + path: `${fields[field]}[${i}].${child.field}`, + span: unref(child.span) + }, + () => getField(child, fields[field][i]) + ) + }) + + //initialize the component by using data + const getChildren = ({ disabled }: { disabled: boolean }) => + fields[field].map((item: object, i: number) => { + return h(NGrid, { xGap: 10 }, () => [ + ...getChild(item, i), + h( + NGridItem, + { + span: 2, + style: { alignSelf: 'center' } + }, + () => + h( + NButton, + { + circle: true, + type: 'error', + size: 'tiny', + disabled, + onClick: () => { + fields[field].splice(i, 1) + } + }, + { + icon: () => h(DeleteOutlined) + } + ) + ) + ]) + }) + + return h( + MultiCondition, + { + name: field, + onAdd: () => { + const newCondition = {} as any + children.map((child: IJsonItem) => { + if (child.field) { + newCondition[child.field] = null + } + }) + fields[field].push(newCondition) + } + }, + { + default: getChildren + } + ) +} diff --git a/dolphinscheduler-ui-next/src/components/form/types.ts b/dolphinscheduler-ui-next/src/components/form/types.ts index 923c07aebb..7c164c95ca 100644 --- a/dolphinscheduler-ui-next/src/components/form/types.ts +++ b/dolphinscheduler-ui-next/src/components/form/types.ts @@ -36,6 +36,7 @@ type IType = | 'tree-select' | 'multi-input' | 'custom' + | 'multi-condition' interface IOption extends SelectOption, TreeSelectOption { label: string diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index b89c749126..fde10bd784 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts @@ -761,7 +761,9 @@ const project = { sea_tunnel_master_url: 'Master URL', sea_tunnel_queue: 'Queue', sea_tunnel_master_url_tips: - 'Please enter the master url, e.g., 127.0.0.1:7077' + 'Please enter the master url, e.g., 127.0.0.1:7077', + switch_condition: 'Condition', + switch_branch_flow: 'Branch Flow' } } diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts index 0c187ddd7e..4ad6a96c39 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts @@ -752,7 +752,9 @@ const project = { sea_tunnel_master: 'Master', sea_tunnel_master_url: 'Master URL', sea_tunnel_queue: '队列', - sea_tunnel_master_url_tips: '请直接填写地址,例如:127.0.0.1:7077' + sea_tunnel_master_url_tips: '请直接填写地址,例如:127.0.0.1:7077', + switch_condition: '条件', + switch_branch_flow: '分支流转' } } diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts index 8f55ac773c..bc84d5fcdb 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts @@ -46,3 +46,4 @@ export { useHttp } from './use-http' export { useSql } from './use-sql' export { useSqoop } from './use-sqoop' export { useSeaTunnel } from './use-sea-tunnel' +export { useSwitch } from './use-switch' diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-switch.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-switch.ts new file mode 100644 index 0000000000..34ad995e48 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-switch.ts @@ -0,0 +1,107 @@ +/* + * 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 { nextTick, onMounted, ref, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { queryProcessDefinitionByCode } from '@/service/modules/process-definition' + +export function useSwitch( + model: { [field: string]: any }, + projectCode: number +): IJsonItem[] { + const { t } = useI18n() + const branchFlowOptions = ref([] as any) + + const loading = ref(false) + + const getOtherTaskDefinitionList = async () => { + if (loading.value) return + loading.value = true + branchFlowOptions.value = [] + try { + const res = await queryProcessDefinitionByCode( + model.processName, + projectCode + ) + res?.taskDefinitionList.forEach((item: any) => { + if (item.code != model.code) { + branchFlowOptions.value.push({ label: item.name, value: item.code }) + } + }) + loading.value = false + } catch (err) { + loading.value = false + } + } + + watch( + () => [model.processName, model.nextCode], + () => { + if (model.processName) { + getOtherTaskDefinitionList() + } + } + ) + + return [ + { + type: 'multi-condition', + field: 'dependTaskList', + name: t('project.node.switch_condition'), + validate: { + required: true + }, + children: [ + { + type: 'input', + field: 'condition', + span: 24, + props: { + loading: loading, + type: 'textarea', + autosize: { minRows: 2 } + }, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'select', + field: 'nextNode', + span: 18, + name: t('project.node.switch_branch_flow'), + options: branchFlowOptions, + validate: { + trigger: ['input', 'blur'], + required: true + } + } + ] + }, + { + type: 'select', + field: 'nextNode', + span: 24, + name: t('project.node.switch_branch_flow'), + props: { + loading: loading + }, + options: branchFlowOptions + } + ] +} diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts index d30aefbaf9..76c8777723 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts @@ -191,6 +191,12 @@ export function formatParams(data: INodeData): { buildRawScript(data) } + if (data.taskType === 'SWITCH') { + taskParams.switchResult = {} + taskParams.switchResult.dependTaskList = data.dependTaskList + taskParams.switchResult.nextNode = data.nextNode + } + const params = { processDefinitionCode: data.processName ? String(data.processName) : '', upstreamCodes: data?.preTasks?.join(','), @@ -325,6 +331,14 @@ export function formatModel(data: ITaskData) { params.rawScript = data.taskParams?.rawScript } + if (data.taskParams?.switchResult) { + params.switchResult = data.taskParams.switchResult + params.dependTaskList = data.taskParams.switchResult?.dependTaskList + ? data.taskParams.switchResult?.dependTaskList + : [] + params.nextNode = data.taskParams.switchResult?.nextNode + } + return params } diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/tasks/use-switch.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/tasks/use-switch.ts new file mode 100644 index 0000000000..25b041bdf4 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/tasks/use-switch.ts @@ -0,0 +1,85 @@ +/* + * 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 } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useSwitch({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'SWITCH', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + rawScript: '', + switchResult: {}, + dependTaskList: [], + nextNode: undefined + } as INodeData) + + let extra: IJsonItem[] = [] + if (from === 1) { + extra = [ + Fields.useTaskType(model, readonly), + Fields.useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName, + code: data?.code + }) + ] + } + + return { + json: [ + Fields.useName(), + ...extra, + Fields.useRunFlag(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useSwitch(model, projectCode), + Fields.usePreTasks(model) + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts index b46ac37530..d9a6a9c422 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts @@ -47,6 +47,16 @@ interface ILocalParam { value?: string } +interface IDependTask { + condition: string + nextNode: number +} + +interface ISwitchResult { + dependTaskList?: IDependTask[] + nextNode?: number +} + interface ISourceItem { id: number } @@ -186,6 +196,9 @@ interface ITaskParams { sourceParams?: string queue?: string master?: string + switchResult?: ISwitchResult + dependTaskList?: IDependTask[] + nextNode?: number } type ITaskType = TaskType diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts index 15b8feab2d..85735f6d6c 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts @@ -27,6 +27,7 @@ import { useSql } from './tasks/use-sql' import { useProcedure } from './tasks/use-procedure' import { useSqoop } from './tasks/use-sqoop' import { useSeaTunnel } from './tasks/use-sea-tunnel' +import { useSwitch } from './tasks/use-switch' import { IJsonItem, INodeData, ITaskData } from './types' export function useTask({ @@ -139,5 +140,14 @@ export function useTask({ }) } + if (taskType === 'SWITCH') { + node = useSwitch({ + projectCode, + from, + readonly, + data + }) + } + return node } diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/status.module.scss b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/status.module.scss index 93a89af84a..41b13a9276 100644 --- a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/status.module.scss +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/status.module.scss @@ -15,7 +15,7 @@ * limitations under the License. */ - .status-icon { +.status-icon { width: 100%; height: 100%; display: block;