Browse Source

[Fix][UI Next][V1.0.0-Alpha] Support workflow batch operation (#8930)

* workflow support batch delete

* workflow support batch export

* support batch copy

* modify batch button styles

* add blank after scss
3.0.0/version-upgrade
Devosend 2 years ago committed by GitHub
parent
commit
dde81eb93c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  2. 7
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  3. 2
      dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts
  4. 115
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/copy-modal.tsx
  5. 7
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx
  6. 23
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-form.ts
  7. 23
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-modal.ts
  8. 9
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.module.scss
  9. 90
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx
  10. 57
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts

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

@ -406,6 +406,7 @@ const project = {
tree_view: 'Tree View',
tree_limit: 'Limit Size',
export: 'Export',
batch_copy: 'Batch Copy',
version_info: 'Version Info',
version: 'Version',
file_upload: 'File Upload',
@ -509,7 +510,11 @@ const project = {
cancel_full_screen: 'Cancel full screen',
task_state: 'Task status',
mode_of_dependent: 'Mode of dependent',
open: 'Open'
open: 'Open',
project_name_required: 'Project name is required',
related_items: 'Related items',
project_name: 'Project Name',
project_tips: 'Please select project name'
},
task: {
task_name: 'Task Name',

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

@ -403,6 +403,7 @@ const project = {
tree_view: '工作流树形图',
tree_limit: '限制大小',
export: '导出',
batch_copy: '批量复制',
version_info: '版本信息',
version: '版本',
file_upload: '文件上传',
@ -506,7 +507,11 @@ const project = {
cancel_full_screen: '取消全屏',
task_state: '任务状态',
mode_of_dependent: '依赖模式',
open: '打开'
open: '打开',
project_name_required: '项目名称必填',
related_items: '关联项目',
project_name: '项目名称',
project_tips: '请选择项目'
},
task: {
task_name: '任务名称',

2
dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts

@ -65,7 +65,7 @@ export function batchCopyByCodes(
})
}
export function batchDeleteByCodes(data: CodesReq, code: CodeReq): any {
export function batchDeleteByCodes(data: CodesReq, code: number): any {
return axios({
url: `/projects/${code}/process-definition/batch-delete`,
method: 'post',

115
dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/copy-modal.tsx

@ -0,0 +1,115 @@
/*
* 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,
PropType,
toRefs,
onMounted,
ref,
computed
} from 'vue'
import { useI18n } from 'vue-i18n'
import Modal from '@/components/modal'
import { useForm } from './use-form'
import { useModal } from './use-modal'
import { NForm, NFormItem, NSelect } from 'naive-ui'
import { ProjectList } from '@/service/modules/projects/types'
import { queryProjectCreatedAndAuthorizedByUser } from '@/service/modules/projects'
const props = {
show: {
type: Boolean as PropType<boolean>,
default: false
},
codes: {
type: Array as PropType<Array<string>>,
default: []
}
}
export default defineComponent({
name: 'workflowDefinitionCopy',
props,
emits: ['update:show', 'update:row', 'updateList'],
setup(props, ctx) {
const { copyState } = useForm()
const { handleBatchCopyDefinition } = useModal(copyState, ctx)
const hideModal = () => {
ctx.emit('update:show')
}
const handleCopy = () => {
handleBatchCopyDefinition(props.codes)
}
const projects = ref<ProjectList[]>([])
const projectOptions = computed(() => {
return projects.value.map((t) => ({
label: t.name,
value: t.code
}))
})
onMounted(() => {
queryProjectCreatedAndAuthorizedByUser().then(
(res: Array<ProjectList>) => {
projects.value = res
}
)
})
return {
hideModal,
handleCopy,
projectOptions,
...toRefs(copyState)
}
},
render() {
const { t } = useI18n()
return (
<Modal
show={this.$props.show}
title={t('project.workflow.related_items')}
onCancel={this.hideModal}
onConfirm={this.handleCopy}
confirmLoading={this.saving}
>
<NForm
rules={this.copyRules}
ref='copyFormRef'
label-placement='left'
label-width='160'
>
<NFormItem
label={t('project.workflow.project_name')}
path='projectCode'
>
<NSelect
options={this.projectOptions}
v-model:value={this.copyForm.projectCode}
placeholder={t('project.workflow.project_tips')}
/>
</NFormItem>
</NForm>
</Modal>
)
}
})

7
dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx

@ -398,7 +398,12 @@ export default defineComponent({
<DeleteOutlined />
</NIcon>
</NButton>
<NButton text type='primary' onClick={this.addStartParams} class='btn-create-custom-parameter'>
<NButton
text
type='primary'
onClick={this.addStartParams}
class='btn-create-custom-parameter'
>
<NIcon>
<PlusCircleOutlined />
</NIcon>

23
dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-form.ts

@ -88,9 +88,30 @@ export const useForm = () => {
},
saving: false
})
const copyState = reactive({
copyFormRef: ref(),
copyForm: {
projectCode: null
},
saving: false,
copyRules: {
projectCode: {
required: true,
trigger: ['input', 'blur'],
validator() {
if (copyState.copyForm.projectCode === '') {
return new Error(t('project.workflow.project_name_required'))
}
}
}
} as FormRules
})
return {
importState,
startState,
timingState
timingState,
copyState
}
}

23
dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-modal.ts

@ -22,6 +22,7 @@ import { useRoute, useRouter } from 'vue-router'
import type { Router } from 'vue-router'
import { format } from 'date-fns'
import {
batchCopyByCodes,
importProcessDefinition,
queryProcessDefinitionByCode
} from '@/service/modules/process-definition'
@ -155,6 +156,27 @@ export function useModal(
}
}
const handleBatchCopyDefinition = async (codes: Array<string>) => {
await state.copyFormRef.validate()
if (state.saving) return
state.saving = true
try {
const data = {
codes: _.join(codes, ','),
targetProjectCode: state.copyForm.projectCode
}
await batchCopyByCodes(data, variables.projectCode)
window.$message.success(t('project.workflow.success'))
state.saving = false
ctx.emit('updateList')
ctx.emit('update:show')
state.copyForm.projectCode = ''
} catch (err) {
state.saving = false
}
}
const getTimingData = () => {
const start = format(
parseTime(state.timingForm.startEndTime[0]),
@ -253,6 +275,7 @@ export function useModal(
handleStartDefinition,
handleCreateTiming,
handleUpdateTiming,
handleBatchCopyDefinition,
getWorkerGroups,
getAlertGroups,
getEnvironmentList,

9
dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.module.scss

@ -86,3 +86,12 @@
width: 86%;
}
}
.batch-button {
position: absolute;
bottom: 10px;
left: 10px;
> div {
margin-right: 5px;
}
}

90
dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx

@ -23,7 +23,9 @@ import {
NIcon,
NInput,
NPagination,
NSpace
NSpace,
NTooltip,
NPopconfirm
} from 'naive-ui'
import { defineComponent, onMounted, toRefs, watch } from 'vue'
import { useI18n } from 'vue-i18n'
@ -32,6 +34,7 @@ import ImportModal from './components/import-modal'
import StartModal from './components/start-modal'
import TimingModal from './components/timing-modal'
import VersionModal from './components/version-modal'
import CopyModal from './components/copy-modal'
import { useRouter, useRoute } from 'vue-router'
import type { Router } from 'vue-router'
import styles from './index.module.scss'
@ -43,7 +46,14 @@ export default defineComponent({
const route = useRoute()
const projectCode = Number(route.params.projectCode)
const { variables, createColumns, getTableData } = useTable()
const {
variables,
createColumns,
getTableData,
batchDeleteWorkflow,
batchExportWorkflow,
batchCopyWorkflow
} = useTable()
const requestData = () => {
getTableData({
@ -57,6 +67,11 @@ export default defineComponent({
requestData()
}
const handleCopyUpdateList = () => {
variables.checkedRowKeys = []
requestData()
}
const handleSearch = () => {
variables.page = 1
requestData()
@ -88,6 +103,10 @@ export default defineComponent({
handleUpdateList,
createDefinition,
handleChangePageSize,
batchDeleteWorkflow,
batchExportWorkflow,
batchCopyWorkflow,
handleCopyUpdateList,
...toRefs(variables)
}
},
@ -99,7 +118,11 @@ export default defineComponent({
<Card class={styles.card}>
<div class={styles.header}>
<NSpace>
<NButton type='primary' onClick={this.createDefinition} class='btn-create-process'>
<NButton
type='primary'
onClick={this.createDefinition}
class='btn-create-process'
>
{t('project.workflow.create_workflow')}
</NButton>
<NButton strong secondary onClick={() => (this.showRef = true)}>
@ -127,11 +150,13 @@ export default defineComponent({
</Card>
<Card title={t('project.workflow.workflow_definition')}>
<NDataTable
rowKey={(row) => row.code}
columns={this.columns}
data={this.tableData}
striped
size={'small'}
class={styles.table}
v-model:checked-row-keys={this.checkedRowKeys}
row-class-name='items'
/>
<div class={styles.pagination}>
@ -146,6 +171,60 @@ export default defineComponent({
onUpdatePageSize={this.handleChangePageSize}
/>
</div>
<div class={styles['batch-button']}>
<NTooltip>
{{
default: () => t('project.workflow.delete'),
trigger: () => (
<NButton
tag='div'
type='primary'
disabled={this.checkedRowKeys.length <= 0}
class='btn-delete-all'
>
<NPopconfirm onPositiveClick={this.batchDeleteWorkflow}>
{{
default: () => t('project.workflow.delete_confirm'),
trigger: () => t('project.workflow.delete')
}}
</NPopconfirm>
</NButton>
)
}}
</NTooltip>
<NTooltip>
{{
default: () => t('project.workflow.export'),
trigger: () => (
<NButton
tag='div'
type='primary'
disabled={this.checkedRowKeys.length <= 0}
onClick={this.batchExportWorkflow}
class='btn-delete-all'
>
{t('project.workflow.export')}
</NButton>
)
}}
</NTooltip>
<NTooltip>
{{
default: () => t('project.workflow.batch_copy'),
trigger: () => (
<NButton
tag='div'
type='primary'
disabled={this.checkedRowKeys.length <= 0}
onClick={() => (this.copyShowRef = true)}
class='btn-delete-all'
>
{t('project.workflow.batch_copy')}
</NButton>
)
}}
</NTooltip>
</div>
</Card>
<ImportModal
v-model:show={this.showRef}
@ -166,6 +245,11 @@ export default defineComponent({
v-model:show={this.versionShowRef}
onUpdateList={this.handleUpdateList}
/>
<CopyModal
v-model:codes={this.checkedRowKeys}
v-model:show={this.copyShowRef}
onUpdateList={this.handleCopyUpdateList}
/>
</div>
)
}

57
dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts

@ -15,14 +15,16 @@
* limitations under the License.
*/
import _ from 'lodash'
import { h, ref, reactive } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import type { Router } from 'vue-router'
import type { TableColumns } from 'naive-ui/es/data-table/src/interface'
import type { TableColumns, RowKey } from 'naive-ui/es/data-table/src/interface'
import { useAsyncState } from '@vueuse/core'
import {
batchCopyByCodes,
batchDeleteByCodes,
batchExportByCodes,
deleteByCode,
queryListPaging,
@ -40,6 +42,7 @@ export function useTable() {
const variables = reactive({
columns: [],
checkedRowKeys: [] as Array<RowKey>,
row: {},
tableData: [],
projectCode: ref(Number(router.currentRoute.value.params.projectCode)),
@ -50,11 +53,17 @@ export function useTable() {
showRef: ref(false),
startShowRef: ref(false),
timingShowRef: ref(false),
versionShowRef: ref(false)
versionShowRef: ref(false),
copyShowRef: ref(false)
})
const createColumns = (variables: any) => {
variables.columns = [
{
type: 'selection',
disabled: (row) => row.releaseState === 'ONLINE',
className: 'btn-selected'
},
{
title: '#',
key: 'id',
@ -200,6 +209,45 @@ export function useTable() {
})
}
const batchDeleteWorkflow = () => {
const data = {
codes: _.join(variables.checkedRowKeys, ',')
}
batchDeleteByCodes(data, variables.projectCode).then(() => {
window.$message.success(t('project.workflow.success'))
if (
variables.tableData.length === variables.checkedRowKeys.length &&
variables.page > 1
) {
variables.page -= 1
}
variables.checkedRowKeys = []
getTableData({
pageSize: variables.pageSize,
pageNo: variables.page,
searchVal: variables.searchVal
})
})
}
const batchExportWorkflow = () => {
const fileName = 'workflow_' + new Date().getTime()
const data = {
codes: _.join(variables.checkedRowKeys, ',')
}
batchExportByCodes(data, variables.projectCode).then((res: any) => {
downloadBlob(res, fileName)
window.$message.success(t('project.workflow.success'))
variables.checkedRowKeys = []
})
}
const batchCopyWorkflow = () => {}
const releaseWorkflow = (row: any) => {
const data = {
name: row.name,
@ -298,6 +346,9 @@ export function useTable() {
return {
variables,
createColumns,
getTableData
getTableData,
batchDeleteWorkflow,
batchExportWorkflow,
batchCopyWorkflow
}
}

Loading…
Cancel
Save