[3.0.1-prepare][cherry-pick]3.0.1 UI 1 (#12033)

* [Improvement][UI] Unified local parameters UI (#11190)

* [Fix][UI] fix bug where icons are displayed in one line. (#11320)

* cherry pick [Improvement-11386][UI] Concise the logic available for task action buttons

* [Fix][UI] Fix the preTask options are unavailable when creating a tas...

* fix build

Co-authored-by: Chris Ho <realhezean@gmail.com>
Co-authored-by: Devosend <devosend@gmail.com>
Co-authored-by: Sheldon <39169452+sketchmind@users.noreply.github.com>
Co-authored-by: Amy0104 <amywang0104@163.com>
This commit is contained in:
Kerwin 2022-09-19 10:41:06 +08:00 committed by GitHub
parent 827eb60dbf
commit ffb58c1e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 183 additions and 448 deletions

View File

@ -47,6 +47,7 @@ export { useExecutorMemory } from './use-executor-memory'
export { useExecutorCores } from './use-executor-cores'
export { useMainJar } from './use-main-jar'
export { useResources } from './use-resources'
export { useTaskDefinition } from './use-task-definition'
export { useShell } from './use-shell'
export { useSpark } from './use-spark'

View File

@ -33,120 +33,76 @@ export function useCustomParams({
}): IJsonItem[] {
const { t } = useI18n()
if (isSimple) {
return [
{
type: 'custom-parameters',
field: field,
name: t(`project.node.${name}`),
class: 'btn-custom-parameters',
span,
children: [
{
type: 'input',
field: 'prop',
span: 10,
class: 'input-param-key',
props: {
placeholder: t('project.node.prop_tips'),
maxLength: 256
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(validate: any, value: string) {
if (!value) {
return new Error(t('project.node.prop_tips'))
}
return [
{
type: 'custom-parameters',
field: field,
name: t(`project.node.${name}`),
class: 'btn-custom-parameters',
span,
children: [
{
type: 'input',
field: 'prop',
span: 6,
class: 'input-param-key',
props: {
placeholder: t('project.node.prop_tips'),
maxLength: 256
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(validate: any, value: string) {
if (!value) {
return new Error(t('project.node.prop_tips'))
}
const sameItems = model[field].filter(
(item: { prop: string }) => item.prop === value
)
const sameItems = model[field].filter(
(item: { prop: string }) => item.prop === value
)
if (sameItems.length > 1) {
return new Error(t('project.node.prop_repeat'))
}
if (sameItems.length > 1) {
return new Error(t('project.node.prop_repeat'))
}
}
},
{
type: 'input',
field: 'value',
span: 10,
class: 'input-param-value',
props: {
placeholder: t('project.node.value_tips'),
maxLength: 256
}
}
]
}
]
} else {
return [
{
type: 'custom-parameters',
field: field,
name: t(`project.node.${name}`),
class: 'btn-custom-parameters',
span,
children: [
{
type: 'input',
field: 'prop',
span: 6,
class: 'input-param-key',
props: {
placeholder: t('project.node.prop_tips'),
maxLength: 256
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(validate: any, value: string) {
if (!value) {
return new Error(t('project.node.prop_tips'))
}
const sameItems = model[field].filter(
(item: { prop: string }) => item.prop === value
)
if (sameItems.length > 1) {
return new Error(t('project.node.prop_repeat'))
}
}
}
},
{
type: 'select',
field: 'direct',
span: 4,
options: DIRECT_LIST,
value: 'IN'
},
{
type: 'select',
field: 'type',
span: 6,
options: TYPE_LIST,
value: 'VARCHAR'
},
{
type: 'input',
field: 'value',
span: 6,
class: 'input-param-value',
props: {
placeholder: t('project.node.value_tips'),
maxLength: 256
}
},
{
type: 'select',
field: 'direct',
span: 4,
options: DIRECT_LIST,
value: 'IN',
props: {
disabled: isSimple
}
]
}
]
}
},
{
type: 'select',
field: 'type',
span: 6,
options: TYPE_LIST,
value: 'VARCHAR',
props: {
disabled: isSimple
}
},
{
type: 'input',
field: 'value',
span: 6,
class: 'input-param-value',
props: {
placeholder: t('project.node.value_tips'),
maxLength: 256
}
}
]
}
]
}
export const TYPE_LIST = [
{
value: 'VARCHAR',

View File

@ -15,6 +15,7 @@
* limitations under the License.
*/
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useTaskNodeStore } from '@/store/project/task-node'
import type { IJsonItem } from '../types'
@ -22,6 +23,14 @@ import type { IJsonItem } from '../types'
export function usePreTasks(): IJsonItem {
const { t } = useI18n()
const taskStore = useTaskNodeStore()
const options = ref(taskStore.getPreTaskOptions)
watch(
() => taskStore.getPreTaskOptions,
(value) => {
options.value = value
}
)
return {
type: 'select',
@ -33,6 +42,6 @@ export function usePreTasks(): IJsonItem {
multiple: true,
filterable: true
},
options: taskStore.getPreTaskOptions
options
}
}

View File

@ -21,6 +21,7 @@ import {
querySimpleList,
queryProcessDefinitionByCode
} from '@/service/modules/process-definition'
import { useTaskNodeStore } from '@/store/project/task-node'
import type { IJsonItem } from '../types'
export function useProcessName({
@ -28,16 +29,18 @@ export function useProcessName({
projectCode,
isCreate,
from,
processName
processName,
taskCode
}: {
model: { [field: string]: any }
projectCode: number
isCreate: boolean
from?: number
processName?: number
taskCode?: number
}): IJsonItem {
const { t } = useI18n()
const taskStore = useTaskNodeStore()
const options = ref([] as { label: string; value: string }[])
const loading = ref(false)
@ -55,6 +58,7 @@ export function useProcessName({
if (!processCode) return
const res = await queryProcessDefinitionByCode(processCode, projectCode)
model.definition = res
taskStore.updateDefinition(res, taskCode)
}
const onChange = (code: number) => {

View File

@ -0,0 +1,46 @@
/*
* 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 { useTaskType, useProcessName } from '.'
import type { IJsonItem, ITaskData } from '../types'
export const useTaskDefinition = ({
projectCode,
from = 0,
readonly,
data,
model
}: {
projectCode: number
from?: number
readonly?: boolean
data?: ITaskData
model: { [field: string]: any }
}): IJsonItem[] => {
if (from === 0) return []
return [
useTaskType(model, readonly),
useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName,
taskCode: data?.code
})
]
}

View File

@ -49,24 +49,10 @@ export function useConditions({
failedNode: 'failed'
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -60,24 +60,10 @@ export function useDataQuality({
others: '--conf spark.yarn.maxAppAttempts=1'
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -51,24 +51,10 @@ export function useDataX({
postStatements: []
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -51,24 +51,10 @@ export function useDependent({
...data
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -46,24 +46,10 @@ export function useEmr({
timeout: 30
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -55,24 +55,10 @@ export function useFlink({
parallelism: 1
})
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -52,24 +52,10 @@ export function useHttp({
socketTimeout: 60000
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -46,24 +46,10 @@ export function useMr({
programType: 'SCALA'
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -45,24 +45,10 @@ export function usePigeon({
targetJobName: ''
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -49,24 +49,10 @@ export function useProcedure({
method: data?.taskParams?.method
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -47,24 +47,10 @@ export function usePython({
rawScript: ''
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -51,24 +51,10 @@ export function useSeaTunnel({
resourceFiles: []
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -47,24 +47,10 @@ export function useShell({
rawScript: ''
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -54,24 +54,10 @@ export function useSpark({
executorCores: 2
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -54,24 +54,10 @@ export function useSql({
udfs: []
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -65,24 +65,10 @@ export function useSqoop({
concurrency: 1
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -48,24 +48,10 @@ export function useSubProcess({
timeout: 30
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -49,24 +49,10 @@ export function useSwitch({
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
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -45,24 +45,10 @@ export function useZeppelin({
timeout: 30
} as INodeData)
let extra: IJsonItem[] = []
if (from === 1) {
extra = [
Fields.useTaskType(model, readonly),
Fields.useProcessName({
model,
projectCode,
isCreate: !data?.id,
from,
processName: data?.processName
})
]
}
return {
json: [
Fields.useName(from),
...extra,
...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
Fields.useRunFlag(),
Fields.useDescription(),
Fields.useTaskPriority(),

View File

@ -26,15 +26,11 @@ import { IWorkflowTaskInstance } from './types'
import { NButton } from 'naive-ui'
const props = {
startButtonDisplay: {
type: Boolean as PropType<boolean>,
default: true
},
startReadonly: {
startDisplay: {
type: Boolean as PropType<boolean>,
default: false
},
menuReadonly: {
menuDisplay: {
type: Boolean as PropType<boolean>,
default: false
},
@ -131,36 +127,36 @@ export default defineComponent({
class={styles['dag-context-menu']}
style={{ left: `${this.left}px`, top: `${this.top}px` }}
>
{this.startButtonDisplay && (
{this.startDisplay && (
<NButton
class={`${styles['menu-item']}`}
disabled={this.startReadonly}
onClick={this.startRunning}
>
{t('project.node.start')}
</NButton>)
}
<NButton
class={`${styles['menu-item']}`}
disabled={this.menuReadonly}
onClick={this.handleEdit}
>
{t('project.node.edit')}
</NButton>
<NButton
class={`${styles['menu-item']}`}
disabled={this.menuReadonly}
onClick={this.handleCopy}
>
{t('project.node.copy')}
</NButton>
<NButton
class={`${styles['menu-item']}`}
disabled={this.menuReadonly}
onClick={this.handleDelete}
>
{t('project.node.delete')}
</NButton>
{this.menuDisplay && (
<>
<NButton
class={`${styles['menu-item']}`}
onClick={this.handleEdit}
>
{t('project.node.edit')}
</NButton>
<NButton
class={`${styles['menu-item']}`}
onClick={this.handleCopy}
>
{t('project.node.copy')}
</NButton>
<NButton
class={`${styles['menu-item']}`}
onClick={this.handleDelete}
>
{t('project.node.delete')}
</NButton>
</>
)}
{this.taskInstance && (
<NButton
class={`${styles['menu-item']}`}

View File

@ -119,11 +119,11 @@ export default defineComponent({
})
// start button in the dag node menu
const startReadonly = computed(() => {
const startDisplay = computed(() => {
if (props.definition) {
return (
route.name === 'workflow-definition-detail' &&
props.definition!.processDefinition.releaseState === 'NOT_RELEASE'
props.definition!.processDefinition.releaseState === 'ONLINE'
)
} else {
return false
@ -131,17 +131,17 @@ export default defineComponent({
})
// other button in the dag node menu
const menuReadonly = computed(() => {
const menuDisplay = computed(() => {
if (props.instance) {
return (
props.instance.state !== 'WAITING_THREAD' &&
props.instance.state !== 'SUCCESS' &&
props.instance.state !== 'PAUSE' &&
props.instance.state !== 'FAILURE' &&
props.instance.state !== 'STOP'
props.instance.state === 'WAITING_THREAD' ||
props.instance.state === 'SUCCESS' ||
props.instance.state === 'PAUSE' ||
props.instance.state === 'FAILURE' ||
props.instance.state === 'STOP'
)
} else if (props.definition) {
return props.definition!.processDefinition.releaseState === 'ONLINE'
return props.definition!.processDefinition.releaseState === 'OFFLINE'
} else {
return false
}
@ -337,7 +337,7 @@ export default defineComponent({
/>
{!!props.definition && (
<VersionModal
isInstance={props.instance ? true : false}
isInstance={!!props.instance}
v-model:row={props.definition.processDefinition}
v-model:show={versionModalShow.value}
onUpdateList={refreshDetail}
@ -362,9 +362,8 @@ export default defineComponent({
onCancel={taskCancel}
/>
<ContextMenuItem
startButtonDisplay={!props.instance}
startReadonly={startReadonly.value}
menuReadonly={menuReadonly.value}
startDisplay={startDisplay.value}
menuDisplay={menuDisplay.value}
taskInstance={taskInstance.value}
cell={nodeVariables.menuCell as Cell}
visible={nodeVariables.menuVisible}

View File

@ -72,14 +72,6 @@
margin-top: 20px;
}
.operation {
> div {
> div {
margin-right: 5px !important;
}
}
}
.startup {
align-items: center;
> div:first-child {

View File

@ -30,7 +30,6 @@ import {
import { execute } from '@/service/modules/executors'
import TableAction from './components/table-action'
import { renderTableTime, runningType } from '@/common/common'
import styles from './index.module.scss'
import { renderStateCell } from '../../task/instance/use-table'
import {
COLUMN_WIDTH_CONFIG,
@ -175,8 +174,7 @@ export function useTable() {
{
title: t('project.workflow.operation'),
key: 'operation',
...COLUMN_WIDTH_CONFIG['operation'](6),
className: styles.operation,
...COLUMN_WIDTH_CONFIG['operation'](7),
render: (_row: IWorkflowInstance, index: number) =>
h(TableAction, {
row: _row,