You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by so...@apache.org on 2022/03/16 10:01:58 UTC
[dolphinscheduler] branch dev updated: [Fix][UI Next][V1.0.0-Alpha] Support workflow batch operation (#8930)
This is an automated email from the ASF dual-hosted git repository.
songjian pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new dde81eb [Fix][UI Next][V1.0.0-Alpha] Support workflow batch operation (#8930)
dde81eb is described below
commit dde81eb93c88042f415cb5f6e0f55c75d6ef95fb
Author: Devosend <de...@gmail.com>
AuthorDate: Wed Mar 16 17:59:20 2022 +0800
[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
---
.../src/locales/modules/en_US.ts | 7 +-
.../src/locales/modules/zh_CN.ts | 7 +-
.../service/modules/process-definition/index.ts | 2 +-
.../workflow/definition/components/copy-modal.tsx | 115 +++++++++++++++++++++
.../workflow/definition/components/start-modal.tsx | 7 +-
.../workflow/definition/components/use-form.ts | 23 ++++-
.../workflow/definition/components/use-modal.ts | 23 +++++
.../projects/workflow/definition/index.module.scss | 9 ++
.../views/projects/workflow/definition/index.tsx | 90 +++++++++++++++-
.../projects/workflow/definition/use-table.ts | 57 +++++++++-
10 files changed, 329 insertions(+), 11 deletions(-)
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index 7f35f22..1fb7cef 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/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',
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index cf69cfe..efbd217 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/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: '任务名称',
diff --git a/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts b/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts
index 477a61c..b866f51 100644
--- a/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts
+++ b/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',
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/copy-modal.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/copy-modal.tsx
new file mode 100644
index 0000000..487175f
--- /dev/null
+++ b/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>
+ )
+ }
+})
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx
index 832b0d8..4201fe7 100644
--- a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx
+++ b/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>
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-form.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-form.ts
index eacbf17..0d57261 100644
--- a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-form.ts
+++ b/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
}
}
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-modal.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-modal.ts
index e486b16..2ef763e 100644
--- a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-modal.ts
+++ b/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,
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.module.scss b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.module.scss
index 7eac171..72e5e2f 100644
--- a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.module.scss
+++ b/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;
+ }
+}
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx
index 5aa6d50..c16f862 100644
--- a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx
+++ b/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>
)
}
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts
index e05f959..b8c8699 100644
--- a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts
+++ b/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,12 +53,18 @@ 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',
width: 50,
@@ -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
}
}