diff --git a/dolphinscheduler-ui-next/src/env.d.ts b/dolphinscheduler-ui-next/src/env.d.ts index db96b93c11..a1c62d2fb6 100644 --- a/dolphinscheduler-ui-next/src/env.d.ts +++ b/dolphinscheduler-ui-next/src/env.d.ts @@ -30,6 +30,12 @@ declare global { } } +declare global { + interface Navigator { + msSaveBlob?: (blob: any, defaultName?: string) => boolean + } +} + declare namespace jquery {} declare module '*.png' diff --git a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts index 7e78f84147..cffa40cedf 100644 --- a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts +++ b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts @@ -104,7 +104,7 @@ export function useDataList() { }, { label: t('menu.workflow_definition'), - key: `/projects/${menuStore.getProjectCode}/workflow/definitions` + key: `/projects/${menuStore.getProjectCode}/workflow-definition` }, { label: t('menu.workflow_instance'), diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index a81cc26de3..4800632443 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts @@ -353,6 +353,7 @@ const project = { workflow: { workflow_relation: 'Workflow Relation', create_workflow: 'Create Workflow', + import_workflow: 'Import Workflow', workflow_name: 'Workflow Name', current_selection: 'Current Selection', online: 'Online', @@ -365,7 +366,70 @@ const project = { schedule_end_time: 'Schedule End Time', crontab_expression: 'Crontab', workflow_publish_status: 'Workflow Publish Status', - schedule_publish_status: 'Schedule Publish Status' + schedule_publish_status: 'Schedule Publish Status', + workflow_definition: 'Workflow Definition', + id: '#', + status: 'Status', + create_time: 'Create Time', + update_time: 'Update Time', + description: 'Description', + create_user: 'Create User', + modify_user: 'Modify User', + operation: 'Operation', + edit: 'Edit', + start: 'Start', + timing: 'Timing', + timezone: 'Timezone', + upline: 'Online', + copy_workflow: 'Copy Workflow', + cron_manage: 'Cron manage', + delete: 'Delete', + tree_view: 'Tree View', + export: 'Export', + version_info: 'Version Info', + version: 'Version', + file_upload: 'File Upload', + upload_file: 'Upload File', + upload: 'Upload', + file_name: 'File Name', + success: 'Success', + set_parameters_before_starting: 'Please set the parameters before starting', + set_parameters_before_timing: 'Set parameters before timing', + start_and_stop_time: 'Start and stop time', + next_five_execution_times: 'Next five execution times', + execute_time: 'Execute time', + failure_strategy: 'Failure Strategy', + notification_strategy: 'Notification Strategy', + workflow_priority: 'Workflow Priority', + worker_group: 'Worker Group', + environment_name: 'Environment Name', + alarm_group: 'Alarm Group', + complement_data: 'Complement Data', + startup_parameter: 'Startup Parameter', + whether_dry_run: 'Whether Dry-Run', + continue: 'Continue', + end: 'End', + none_send: 'None', + success_send: 'Success', + failure_send: 'Failure', + all_send: 'All', + whether_complement_data: 'Whether it is a complement process?', + schedule_date: 'Schedule date', + mode_of_execution: 'Mode of execution', + serial_execution: 'Serial execution', + parallel_execution: 'Parallel execution', + parallelism: 'Parallelism', + custom_parallelism: 'Custom Parallelism', + please_enter_parallelism: 'Please enter Parallelism', + please_choose: 'Please Choose', + start_time: 'Start Time', + end_time: 'End Time', + crontab: 'Crontab', + delete_confirm: 'Delete?', + enter_name_tips: 'Please enter name', + switch_version: 'Switch To This Version', + confirm_switch_version: 'Confirm Switch To This Version?', + current_version: 'Current Version' }, 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 a2cc2710cc..fecc01b87a 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts @@ -348,6 +348,7 @@ const project = { workflow: { workflow_relation: '工作流关系', create_workflow: '创建工作流', + import_workflow: '导入工作流', workflow_name: '工作流名称', current_selection: '当前选择', online: '已上线', @@ -360,7 +361,73 @@ const project = { schedule_end_time: '定时结束时间', crontab_expression: 'Crontab', workflow_publish_status: '工作流上线状态', - schedule_publish_status: '定时状态' + schedule_publish_status: '定时状态', + workflow_definition: '工作流定义', + id: '编号', + status: '状态', + create_time: '创建时间', + update_time: '更新时间', + description: '描述', + create_user: '创建用户', + modify_user: '修改用户', + operation: '操作', + edit: '编辑', + confirm: '确定', + cancel: '取消', + start: '运行', + timing: '定时', + timezone: '时区', + up_line: '上线', + down_line: '下线', + copy_workflow: '复制工作流', + cron_manage: '定时管理', + delete: '删除', + tree_view: '树形图', + export: '导出', + version_info: '版本信息', + version: '版本', + file_upload: '文件上传', + upload_file: '上传文件', + upload: '上传', + file_name: '文件名称', + success: '成功', + set_parameters_before_starting: '启动前请先设置参数', + set_parameters_before_timing: '定时前请先设置参数', + start_and_stop_time: '起止时间', + next_five_execution_times: '接下来五次执行时间', + execute_time: '执行时间', + failure_strategy: '失败策略', + notification_strategy: '通知策略', + workflow_priority: '流程优先级', + worker_group: 'Worker分组', + environment_name: '环境名称', + alarm_group: '告警组', + complement_data: '补数', + startup_parameter: '启动参数', + whether_dry_run: '是否空跑', + continue: '继续', + end: '结束', + none_send: '都不发', + success_send: '成功发', + failure_send: '失败发', + all_send: '成功或失败都发', + whether_complement_data: '是否是补数', + schedule_date: '调度日期', + mode_of_execution: '执行方式', + serial_execution: '串行执行', + parallel_execution: '并行执行', + parallelism: '并行度', + custom_parallelism: '自定义并行度', + please_enter_parallelism: '请输入并行度', + please_choose: '请选择', + start_time: '开始时间', + end_time: '结束时间', + crontab: 'Crontab', + delete_confirm: '确定删除吗?', + enter_name_tips: '请输入名称', + switch_version: '切换到该版本', + confirm_switch_version: '确定切换到该版本吗?', + current_version: '当前版本' }, task: { task_name: '任务名称', diff --git a/dolphinscheduler-ui-next/src/router/modules/projects.ts b/dolphinscheduler-ui-next/src/router/modules/projects.ts index d594ac8b0d..03f469e95c 100644 --- a/dolphinscheduler-ui-next/src/router/modules/projects.ts +++ b/dolphinscheduler-ui-next/src/router/modules/projects.ts @@ -60,7 +60,7 @@ export default { } }, { - path: '/projects/:projectCode/workflow/definitions', + path: '/projects/:projectCode/workflow-definition', name: 'workflow-definition-list', component: components['projects-workflow-definition'], meta: { @@ -68,6 +68,15 @@ export default { showSide: true } }, + { + path: '/projects/:projectCode/workflow-definition/timing/:definitionCode', + name: 'workflow-definition-timing', + component: components['projects-workflow-definition-timing'], + meta: { + title: '定时管理', + showSide: true + } + }, { path: '/projects/:projectCode/workflow/definitions/create', name: 'workflow-definition-create', diff --git a/dolphinscheduler-ui-next/src/service/modules/executors/index.ts b/dolphinscheduler-ui-next/src/service/modules/executors/index.ts index 6d3dcaaccd..3cc956040f 100644 --- a/dolphinscheduler-ui-next/src/service/modules/executors/index.ts +++ b/dolphinscheduler-ui-next/src/service/modules/executors/index.ts @@ -44,7 +44,7 @@ export function startCheckProcessDefinition( export function startProcessInstance( data: ProcessInstanceReq, - code: ProjectCodeReq + code: number ): any { return axios({ url: `/projects/${code}/executors/start-process-instance`, 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 1bfe0034a3..2d255480ea 100644 --- a/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts +++ b/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts @@ -30,7 +30,7 @@ import { TargetCodeReq } from './types' -export function queryListPaging(params: PageReq & ListReq, code: CodeReq): any { +export function queryListPaging(params: PageReq & ListReq, code: number): any { return axios({ url: `/projects/${code}/process-definition`, method: 'get', @@ -58,7 +58,7 @@ export function queryAllByProjectCode(code: CodeReq): any { export function batchCopyByCodes( data: TargetCodeReq & CodesReq, - code: CodeReq + code: number ): any { return axios({ url: `/projects/${code}/process-definition/batch-copy`, @@ -75,10 +75,11 @@ export function batchDeleteByCodes(data: CodesReq, code: CodeReq): any { }) } -export function batchExportByCodes(data: CodesReq, code: CodeReq): any { +export function batchExportByCodes(data: CodesReq, code: number): any { return axios({ url: `/projects/${code}/process-definition/batch-export`, method: 'post', + responseType: 'blob', data }) } @@ -105,7 +106,7 @@ export function getTaskListByDefinitionCodes( }) } -export function importProcessDefinition(data: FileReq, code: CodeReq): any { +export function importProcessDefinition(data: FormData, code: number): any { return axios({ url: `/projects/${code}/process-definition/import`, method: 'post', @@ -168,7 +169,7 @@ export function update( }) } -export function deleteByCode(code: CodeReq, processCode: CodeReq): any { +export function deleteByCode(code: number, processCode: number): any { return axios({ url: `/projects/${code}/process-definition/${processCode}`, method: 'delete' @@ -177,8 +178,8 @@ export function deleteByCode(code: CodeReq, processCode: CodeReq): any { export function release( data: NameReq & ReleaseStateReq, - code: CodeReq, - processCode: CodeReq + code: number, + processCode: number ): any { return axios({ url: `/projects/${code}/process-definition/${processCode}/release`, @@ -199,8 +200,8 @@ export function getTasksByDefinitionCode( export function queryVersions( params: PageReq, - code: CodeReq, - processCode: CodeReq + code: number, + processCode: number ): any { return axios({ url: `/projects/${code}/process-definition/${processCode}/versions`, @@ -210,9 +211,9 @@ export function queryVersions( } export function switchVersion( - code: CodeReq, - processCode: CodeReq, - version: VersionReq + code: number, + processCode: number, + version: number ): any { return axios({ url: `/projects/${code}/process-definition/${processCode}/versions/${version}`, @@ -221,9 +222,9 @@ export function switchVersion( } export function deleteVersion( - code: CodeReq, - processCode: CodeReq, - version: VersionReq + code: number, + processCode: number, + version: number ): any { return axios({ url: `/projects/${code}/process-definition/${processCode}/versions/${version}`, diff --git a/dolphinscheduler-ui-next/src/service/modules/schedules/index.ts b/dolphinscheduler-ui-next/src/service/modules/schedules/index.ts index 534f243b5f..e8c8557e6a 100644 --- a/dolphinscheduler-ui-next/src/service/modules/schedules/index.ts +++ b/dolphinscheduler-ui-next/src/service/modules/schedules/index.ts @@ -20,16 +20,17 @@ import { ProjectCodeReq, IdReq, CodeReq, + ListReq, ScheduleReq, WorkerGroupIdReq, - ScheduleListReq, CreateScheduleReq, - DeleteScheduleReq + DeleteScheduleReq, + ProcessDefinitionCodeReq } from './types' export function queryScheduleListPaging( - params: ScheduleListReq, - projectCode: ProjectCodeReq + params: ListReq & ProcessDefinitionCodeReq, + projectCode: number ): any { return axios({ url: `/projects/${projectCode}/schedules`, @@ -40,7 +41,7 @@ export function queryScheduleListPaging( export function createSchedule( data: CreateScheduleReq & WorkerGroupIdReq, - projectCode: ProjectCodeReq + projectCode: number ): any { return axios({ url: `/projects/${projectCode}/schedules`, @@ -56,10 +57,7 @@ export function queryScheduleList(projectCode: ProjectCodeReq): any { }) } -export function previewSchedule( - data: ScheduleReq, - projectCode: ProjectCodeReq -): any { +export function previewSchedule(data: ScheduleReq, projectCode: number): any { return axios({ url: `/projects/${projectCode}/schedules/preview`, method: 'post', @@ -81,8 +79,8 @@ export function updateScheduleByProcessDefinitionCode( export function updateSchedule( data: CreateScheduleReq, - projectCode: ProjectCodeReq, - id: IdReq + projectCode: number, + id: number ): any { return axios({ url: `/projects/${projectCode}/schedules/${id}`, @@ -92,24 +90,24 @@ export function updateSchedule( } export function deleteScheduleById( - data: DeleteScheduleReq, - projectCode: ProjectCodeReq + scheduleId: number, + projectCode: number ): any { return axios({ - url: `/projects/${projectCode}/schedules/${data.id}`, + url: `/projects/${projectCode}/schedules/${scheduleId}`, method: 'delete', - data + params: { scheduleId } }) } -export function offline(projectCode: ProjectCodeReq, id: IdReq): any { +export function offline(projectCode: number, id: number): any { return axios({ url: `/projects/${projectCode}/schedules/${id}/offline`, method: 'post' }) } -export function online(projectCode: ProjectCodeReq, id: IdReq): any { +export function online(projectCode: number, id: number): any { return axios({ url: `/projects/${projectCode}/schedules/${id}/online`, method: 'post' diff --git a/dolphinscheduler-ui-next/src/utils/timezone.ts b/dolphinscheduler-ui-next/src/utils/timezone.ts new file mode 100644 index 0000000000..508b3ee047 --- /dev/null +++ b/dolphinscheduler-ui-next/src/utils/timezone.ts @@ -0,0 +1,611 @@ +/* + * 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. + */ + +export const timezoneList = [ + 'Africa/Abidjan', + 'Africa/Accra', + 'Africa/Addis_Ababa', + 'Africa/Algiers', + 'Africa/Asmara', + 'Africa/Asmera', + 'Africa/Bamako', + 'Africa/Bangui', + 'Africa/Banjul', + 'Africa/Bissau', + 'Africa/Blantyre', + 'Africa/Brazzaville', + 'Africa/Bujumbura', + 'Africa/Cairo', + 'Africa/Casablanca', + 'Africa/Ceuta', + 'Africa/Conakry', + 'Africa/Dakar', + 'Africa/Dar_es_Salaam', + 'Africa/Djibouti', + 'Africa/Douala', + 'Africa/El_Aaiun', + 'Africa/Freetown', + 'Africa/Gaborone', + 'Africa/Harare', + 'Africa/Johannesburg', + 'Africa/Juba', + 'Africa/Kampala', + 'Africa/Khartoum', + 'Africa/Kigali', + 'Africa/Kinshasa', + 'Africa/Lagos', + 'Africa/Libreville', + 'Africa/Lome', + 'Africa/Luanda', + 'Africa/Lubumbashi', + 'Africa/Lusaka', + 'Africa/Malabo', + 'Africa/Maputo', + 'Africa/Maseru', + 'Africa/Mbabane', + 'Africa/Mogadishu', + 'Africa/Monrovia', + 'Africa/Nairobi', + 'Africa/Ndjamena', + 'Africa/Niamey', + 'Africa/Nouakchott', + 'Africa/Ouagadougou', + 'Africa/Porto-Novo', + 'Africa/Sao_Tome', + 'Africa/Timbuktu', + 'Africa/Tripoli', + 'Africa/Tunis', + 'Africa/Windhoek', + 'America/Adak', + 'America/Anchorage', + 'America/Anguilla', + 'America/Antigua', + 'America/Araguaina', + 'America/Argentina/Buenos_Aires', + 'America/Argentina/Catamarca', + 'America/Argentina/ComodRivadavia', + 'America/Argentina/Cordoba', + 'America/Argentina/Jujuy', + 'America/Argentina/La_Rioja', + 'America/Argentina/Mendoza', + 'America/Argentina/Rio_Gallegos', + 'America/Argentina/Salta', + 'America/Argentina/San_Juan', + 'America/Argentina/San_Luis', + 'America/Argentina/Tucuman', + 'America/Argentina/Ushuaia', + 'America/Aruba', + 'America/Asuncion', + 'America/Atikokan', + 'America/Atka', + 'America/Bahia', + 'America/Bahia_Banderas', + 'America/Barbados', + 'America/Belem', + 'America/Belize', + 'America/Blanc-Sablon', + 'America/Boa_Vista', + 'America/Bogota', + 'America/Boise', + 'America/Buenos_Aires', + 'America/Cambridge_Bay', + 'America/Campo_Grande', + 'America/Cancun', + 'America/Caracas', + 'America/Catamarca', + 'America/Cayenne', + 'America/Cayman', + 'America/Chicago', + 'America/Chihuahua', + 'America/Coral_Harbour', + 'America/Cordoba', + 'America/Costa_Rica', + 'America/Creston', + 'America/Cuiaba', + 'America/Curacao', + 'America/Danmarkshavn', + 'America/Dawson', + 'America/Dawson_Creek', + 'America/Denver', + 'America/Detroit', + 'America/Dominica', + 'America/Edmonton', + 'America/Eirunepe', + 'America/El_Salvador', + 'America/Ensenada', + 'America/Fort_Nelson', + 'America/Fort_Wayne', + 'America/Fortaleza', + 'America/Glace_Bay', + 'America/Godthab', + 'America/Goose_Bay', + 'America/Grand_Turk', + 'America/Grenada', + 'America/Guadeloupe', + 'America/Guatemala', + 'America/Guayaquil', + 'America/Guyana', + 'America/Halifax', + 'America/Havana', + 'America/Hermosillo', + 'America/Indiana/Indianapolis', + 'America/Indiana/Knox', + 'America/Indiana/Marengo', + 'America/Indiana/Petersburg', + 'America/Indiana/Tell_City', + 'America/Indiana/Vevay', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Indianapolis', + 'America/Inuvik', + 'America/Iqaluit', + 'America/Jamaica', + 'America/Jujuy', + 'America/Juneau', + 'America/Kentucky/Louisville', + 'America/Kentucky/Monticello', + 'America/Knox_IN', + 'America/Kralendijk', + 'America/La_Paz', + 'America/Lima', + 'America/Los_Angeles', + 'America/Louisville', + 'America/Lower_Princes', + 'America/Maceio', + 'America/Managua', + 'America/Manaus', + 'America/Marigot', + 'America/Martinique', + 'America/Matamoros', + 'America/Mazatlan', + 'America/Mendoza', + 'America/Menominee', + 'America/Merida', + 'America/Metlakatla', + 'America/Mexico_City', + 'America/Miquelon', + 'America/Moncton', + 'America/Monterrey', + 'America/Montevideo', + 'America/Montreal', + 'America/Montserrat', + 'America/Nassau', + 'America/New_York', + 'America/Nipigon', + 'America/Nome', + 'America/Noronha', + 'America/North_Dakota/Beulah', + 'America/North_Dakota/Center', + 'America/North_Dakota/New_Salem', + 'America/Ojinaga', + 'America/Panama', + 'America/Pangnirtung', + 'America/Paramaribo', + 'America/Phoenix', + 'America/Port-au-Prince', + 'America/Port_of_Spain', + 'America/Porto_Acre', + 'America/Porto_Velho', + 'America/Puerto_Rico', + 'America/Punta_Arenas', + 'America/Rainy_River', + 'America/Rankin_Inlet', + 'America/Recife', + 'America/Regina', + 'America/Resolute', + 'America/Rio_Branco', + 'America/Rosario', + 'America/Santa_Isabel', + 'America/Santarem', + 'America/Santiago', + 'America/Santo_Domingo', + 'America/Sao_Paulo', + 'America/Scoresbysund', + 'America/Shiprock', + 'America/Sitka', + 'America/St_Barthelemy', + 'America/St_Johns', + 'America/St_Kitts', + 'America/St_Lucia', + 'America/St_Thomas', + 'America/St_Vincent', + 'America/Swift_Current', + 'America/Tegucigalpa', + 'America/Thule', + 'America/Thunder_Bay', + 'America/Tijuana', + 'America/Toronto', + 'America/Tortola', + 'America/Vancouver', + 'America/Virgin', + 'America/Whitehorse', + 'America/Winnipeg', + 'America/Yakutat', + 'America/Yellowknife', + 'Antarctica/Casey', + 'Antarctica/Davis', + 'Antarctica/DumontDUrville', + 'Antarctica/Macquarie', + 'Antarctica/Mawson', + 'Antarctica/McMurdo', + 'Antarctica/Palmer', + 'Antarctica/Rothera', + 'Antarctica/South_Pole', + 'Antarctica/Syowa', + 'Antarctica/Troll', + 'Antarctica/Vostok', + 'Arctic/Longyearbyen', + 'Asia/Aden', + 'Asia/Almaty', + 'Asia/Amman', + 'Asia/Anadyr', + 'Asia/Aqtau', + 'Asia/Aqtobe', + 'Asia/Ashgabat', + 'Asia/Ashkhabad', + 'Asia/Atyrau', + 'Asia/Baghdad', + 'Asia/Bahrain', + 'Asia/Baku', + 'Asia/Bangkok', + 'Asia/Barnaul', + 'Asia/Beirut', + 'Asia/Bishkek', + 'Asia/Brunei', + 'Asia/Calcutta', + 'Asia/Chita', + 'Asia/Choibalsan', + 'Asia/Chongqing', + 'Asia/Chungking', + 'Asia/Colombo', + 'Asia/Dacca', + 'Asia/Damascus', + 'Asia/Dhaka', + 'Asia/Dili', + 'Asia/Dubai', + 'Asia/Dushanbe', + 'Asia/Famagusta', + 'Asia/Gaza', + 'Asia/Harbin', + 'Asia/Hebron', + 'Asia/Ho_Chi_Minh', + 'Asia/Hong_Kong', + 'Asia/Hovd', + 'Asia/Irkutsk', + 'Asia/Istanbul', + 'Asia/Jakarta', + 'Asia/Jayapura', + 'Asia/Jerusalem', + 'Asia/Kabul', + 'Asia/Kamchatka', + 'Asia/Karachi', + 'Asia/Kashgar', + 'Asia/Kathmandu', + 'Asia/Katmandu', + 'Asia/Khandyga', + 'Asia/Kolkata', + 'Asia/Krasnoyarsk', + 'Asia/Kuala_Lumpur', + 'Asia/Kuching', + 'Asia/Kuwait', + 'Asia/Macao', + 'Asia/Macau', + 'Asia/Magadan', + 'Asia/Makassar', + 'Asia/Manila', + 'Asia/Muscat', + 'Asia/Nicosia', + 'Asia/Novokuznetsk', + 'Asia/Novosibirsk', + 'Asia/Omsk', + 'Asia/Oral', + 'Asia/Phnom_Penh', + 'Asia/Pontianak', + 'Asia/Pyongyang', + 'Asia/Qatar', + 'Asia/Qyzylorda', + 'Asia/Rangoon', + 'Asia/Riyadh', + 'Asia/Saigon', + 'Asia/Sakhalin', + 'Asia/Samarkand', + 'Asia/Seoul', + 'Asia/Shanghai', + 'Asia/Singapore', + 'Asia/Srednekolymsk', + 'Asia/Taipei', + 'Asia/Tashkent', + 'Asia/Tbilisi', + 'Asia/Tehran', + 'Asia/Tel_Aviv', + 'Asia/Thimbu', + 'Asia/Thimphu', + 'Asia/Tokyo', + 'Asia/Tomsk', + 'Asia/Ujung_Pandang', + 'Asia/Ulaanbaatar', + 'Asia/Ulan_Bator', + 'Asia/Urumqi', + 'Asia/Ust-Nera', + 'Asia/Vientiane', + 'Asia/Vladivostok', + 'Asia/Yakutsk', + 'Asia/Yangon', + 'Asia/Yekaterinburg', + 'Asia/Yerevan', + 'Atlantic/Azores', + 'Atlantic/Bermuda', + 'Atlantic/Canary', + 'Atlantic/Cape_Verde', + 'Atlantic/Faeroe', + 'Atlantic/Faroe', + 'Atlantic/Jan_Mayen', + 'Atlantic/Madeira', + 'Atlantic/Reykjavik', + 'Atlantic/South_Georgia', + 'Atlantic/St_Helena', + 'Atlantic/Stanley', + 'Australia/ACT', + 'Australia/Adelaide', + 'Australia/Brisbane', + 'Australia/Broken_Hill', + 'Australia/Canberra', + 'Australia/Currie', + 'Australia/Darwin', + 'Australia/Eucla', + 'Australia/Hobart', + 'Australia/LHI', + 'Australia/Lindeman', + 'Australia/Lord_Howe', + 'Australia/Melbourne', + 'Australia/NSW', + 'Australia/North', + 'Australia/Perth', + 'Australia/Queensland', + 'Australia/South', + 'Australia/Sydney', + 'Australia/Tasmania', + 'Australia/Victoria', + 'Australia/West', + 'Australia/Yancowinna', + 'Brazil/Acre', + 'Brazil/DeNoronha', + 'Brazil/East', + 'Brazil/West', + 'CET', + 'CST6CDT', + 'Canada/Atlantic', + 'Canada/Central', + 'Canada/Eastern', + 'Canada/Mountain', + 'Canada/Newfoundland', + 'Canada/Pacific', + 'Canada/Saskatchewan', + 'Canada/Yukon', + 'Chile/Continental', + 'Chile/EasterIsland', + 'Cuba', + 'EET', + 'EST', + 'EST5EDT', + 'Egypt', + 'Eire', + 'Etc/GMT', + 'Etc/GMT+0', + 'Etc/GMT+1', + 'Etc/GMT+10', + 'Etc/GMT+11', + 'Etc/GMT+12', + 'Etc/GMT+2', + 'Etc/GMT+3', + 'Etc/GMT+4', + 'Etc/GMT+5', + 'Etc/GMT+6', + 'Etc/GMT+7', + 'Etc/GMT+8', + 'Etc/GMT+9', + 'Etc/GMT-0', + 'Etc/GMT-1', + 'Etc/GMT-10', + 'Etc/GMT-11', + 'Etc/GMT-12', + 'Etc/GMT-13', + 'Etc/GMT-14', + 'Etc/GMT-2', + 'Etc/GMT-3', + 'Etc/GMT-4', + 'Etc/GMT-5', + 'Etc/GMT-6', + 'Etc/GMT-7', + 'Etc/GMT-8', + 'Etc/GMT-9', + 'Etc/GMT0', + 'Etc/Greenwich', + 'Etc/UCT', + 'Etc/UTC', + 'Etc/Universal', + 'Etc/Zulu', + 'Europe/Amsterdam', + 'Europe/Andorra', + 'Europe/Astrakhan', + 'Europe/Athens', + 'Europe/Belfast', + 'Europe/Belgrade', + 'Europe/Berlin', + 'Europe/Bratislava', + 'Europe/Brussels', + 'Europe/Bucharest', + 'Europe/Budapest', + 'Europe/Busingen', + 'Europe/Chisinau', + 'Europe/Copenhagen', + 'Europe/Dublin', + 'Europe/Gibraltar', + 'Europe/Guernsey', + 'Europe/Helsinki', + 'Europe/Isle_of_Man', + 'Europe/Istanbul', + 'Europe/Jersey', + 'Europe/Kaliningrad', + 'Europe/Kiev', + 'Europe/Kirov', + 'Europe/Lisbon', + 'Europe/Ljubljana', + 'Europe/London', + 'Europe/Luxembourg', + 'Europe/Madrid', + 'Europe/Malta', + 'Europe/Mariehamn', + 'Europe/Minsk', + 'Europe/Monaco', + 'Europe/Moscow', + 'Europe/Nicosia', + 'Europe/Oslo', + 'Europe/Paris', + 'Europe/Podgorica', + 'Europe/Prague', + 'Europe/Riga', + 'Europe/Rome', + 'Europe/Samara', + 'Europe/San_Marino', + 'Europe/Sarajevo', + 'Europe/Saratov', + 'Europe/Simferopol', + 'Europe/Skopje', + 'Europe/Sofia', + 'Europe/Stockholm', + 'Europe/Tallinn', + 'Europe/Tirane', + 'Europe/Tiraspol', + 'Europe/Ulyanovsk', + 'Europe/Uzhgorod', + 'Europe/Vaduz', + 'Europe/Vatican', + 'Europe/Vienna', + 'Europe/Vilnius', + 'Europe/Volgograd', + 'Europe/Warsaw', + 'Europe/Zagreb', + 'Europe/Zaporozhye', + 'Europe/Zurich', + 'GB', + 'GB-Eire', + 'GMT', + 'GMT+0', + 'GMT-0', + 'GMT0', + 'Greenwich', + 'HST', + 'Hongkong', + 'Iceland', + 'Indian/Antananarivo', + 'Indian/Chagos', + 'Indian/Christmas', + 'Indian/Cocos', + 'Indian/Comoro', + 'Indian/Kerguelen', + 'Indian/Mahe', + 'Indian/Maldives', + 'Indian/Mauritius', + 'Indian/Mayotte', + 'Indian/Reunion', + 'Iran', + 'Israel', + 'Jamaica', + 'Japan', + 'Kwajalein', + 'Libya', + 'MET', + 'MST', + 'MST7MDT', + 'Mexico/BajaNorte', + 'Mexico/BajaSur', + 'Mexico/General', + 'NZ', + 'NZ-CHAT', + 'Navajo', + 'PRC', + 'PST8PDT', + 'Pacific/Apia', + 'Pacific/Auckland', + 'Pacific/Bougainville', + 'Pacific/Chatham', + 'Pacific/Chuuk', + 'Pacific/Easter', + 'Pacific/Efate', + 'Pacific/Enderbury', + 'Pacific/Fakaofo', + 'Pacific/Fiji', + 'Pacific/Funafuti', + 'Pacific/Galapagos', + 'Pacific/Gambier', + 'Pacific/Guadalcanal', + 'Pacific/Guam', + 'Pacific/Honolulu', + 'Pacific/Johnston', + 'Pacific/Kiritimati', + 'Pacific/Kosrae', + 'Pacific/Kwajalein', + 'Pacific/Majuro', + 'Pacific/Marquesas', + 'Pacific/Midway', + 'Pacific/Nauru', + 'Pacific/Niue', + 'Pacific/Norfolk', + 'Pacific/Noumea', + 'Pacific/Pago_Pago', + 'Pacific/Palau', + 'Pacific/Pitcairn', + 'Pacific/Pohnpei', + 'Pacific/Ponape', + 'Pacific/Port_Moresby', + 'Pacific/Rarotonga', + 'Pacific/Saipan', + 'Pacific/Samoa', + 'Pacific/Tahiti', + 'Pacific/Tarawa', + 'Pacific/Tongatapu', + 'Pacific/Truk', + 'Pacific/Wake', + 'Pacific/Wallis', + 'Pacific/Yap', + 'Poland', + 'Portugal', + 'ROC', + 'ROK', + 'Singapore', + 'Turkey', + 'UCT', + 'US/Alaska', + 'US/Aleutian', + 'US/Arizona', + 'US/Central', + 'US/East-Indiana', + 'US/Eastern', + 'US/Hawaii', + 'US/Indiana-Starke', + 'US/Michigan', + 'US/Mountain', + 'US/Pacific', + 'US/Pacific-New', + 'US/Samoa', + 'UTC', + 'Universal', + 'W-SU', + 'WET', + 'Zulu' +] diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/import-modal.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/import-modal.tsx new file mode 100644 index 0000000000..a1f766ca53 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/import-modal.tsx @@ -0,0 +1,103 @@ +/* + * 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 } 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, NButton, NUpload, NIcon, NInput } from 'naive-ui' +import { CloudUploadOutlined } from '@vicons/antd' + +const props = { + show: { + type: Boolean as PropType, + default: false + } +} + +export default defineComponent({ + name: 'workflowDefinitionImport', + props, + emits: ['update:show', 'update:row', 'updateList'], + setup(props, ctx) { + const { importState } = useForm() + const { handleImportDefinition } = useModal(importState, ctx) + const hideModal = () => { + ctx.emit('update:show') + } + + const handleImport = () => { + handleImportDefinition() + } + + const customRequest = ({ file }: any) => { + importState.importForm.name = file.name + importState.importForm.file = file.file + } + + return { + hideModal, + handleImport, + customRequest, + ...toRefs(importState) + } + }, + + render() { + const { t } = useI18n() + + return ( + + + + + + + 上传 + + + + + + + + + + + + + ) + } +}) 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 new file mode 100644 index 0000000000..9d5f543fa7 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx @@ -0,0 +1,388 @@ +/* + * 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, h, onMounted, ref } 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, + NButton, + NIcon, + NInput, + NSpace, + NRadio, + NRadioGroup, + NSelect, + NSwitch, + NCheckbox, + NDatePicker +} from 'naive-ui' +import { + ArrowDownOutlined, + ArrowUpOutlined, + DeleteOutlined, + PlusCircleOutlined +} from '@vicons/antd' +import { IDefinitionData } from '../types' +import styles from '../index.module.scss' + +const props = { + row: { + type: Object as PropType, + default: {} + }, + show: { + type: Boolean as PropType, + default: false + } +} + +export default defineComponent({ + name: 'workflowDefinitionStart', + props, + emits: ['update:show', 'update:row', 'updateList'], + setup(props, ctx) { + const parallelismRef = ref(false) + const { t } = useI18n() + const { startState } = useForm() + const { + variables, + handleStartDefinition, + getWorkerGroups, + getAlertGroups, + getEnvironmentList + } = useModal(startState, ctx) + + const hideModal = () => { + ctx.emit('update:show') + } + + const handleStart = () => { + handleStartDefinition(props.row.code) + } + + const generalWarningTypeListOptions = () => [ + { + value: 'NONE', + label: t('project.workflow.none_send') + }, + { + value: 'SUCCESS', + label: t('project.workflow.success_send') + }, + { + value: 'FAILURE', + label: t('project.workflow.failure_send') + }, + { + value: 'ALL', + label: t('project.workflow.all_send') + } + ] + + const generalPriorityList = () => [ + { + value: 'HIGHEST', + label: 'HIGHEST', + color: '#ff0000', + icon: ArrowUpOutlined + }, + { + value: 'HIGH', + label: 'HIGH', + color: '#ff0000', + icon: ArrowUpOutlined + }, + { + value: 'MEDIUM', + label: 'MEDIUM', + color: '#EA7D24', + icon: ArrowUpOutlined + }, + { + value: 'LOW', + label: 'LOW', + color: '#2A8734', + icon: ArrowDownOutlined + }, + { + value: 'LOWEST', + label: 'LOWEST', + color: '#2A8734', + icon: ArrowDownOutlined + } + ] + + const renderLabel = (option: any) => { + return [ + h( + NIcon, + { + style: { + verticalAlign: 'middle', + marginRight: '4px', + marginBottom: '3px' + }, + color: option.color + }, + { + default: () => h(option.icon) + } + ), + option.label + ] + } + + const updateWorkerGroup = () => { + startState.startForm.environmentCode = null + } + + const addStartParams = () => { + variables.startParamsList.push({ + prop: '', + value: '' + }) + } + + const updateParamsList = (index: number, param: Array) => { + variables.startParamsList[index].prop = param[0] + variables.startParamsList[index].value = param[1] + } + + const removeStartParams = (index: number) => { + variables.startParamsList.splice(index, 1) + } + + onMounted(() => { + getWorkerGroups() + getAlertGroups() + getEnvironmentList() + }) + + return { + t, + parallelismRef, + hideModal, + handleStart, + generalWarningTypeListOptions, + generalPriorityList, + renderLabel, + updateWorkerGroup, + removeStartParams, + addStartParams, + updateParamsList, + ...toRefs(variables), + ...toRefs(startState), + ...toRefs(props) + } + }, + + render() { + const { t } = this + + return ( + + + + {this.row.name} + + + + + + {t('project.workflow.continue')} + + {t('project.workflow.end')} + + + + + + + + + + + + + + + item.workerGroups?.includes(this.startForm.workerGroup) + )} + v-model:value={this.startForm.environmentCode} + /> + + + + + + + {t('project.workflow.whether_complement_data')} + + + {this.startForm.execType && ( + + + + + + {t('project.workflow.serial_execution')} + + + {t('project.workflow.parallel_execution')} + + + + + {this.startForm.runMode === 'RUN_MODE_PARALLEL' && ( + + + {t('project.workflow.custom_parallelism')} + + + + )} + + + + + )} + + {this.startParamsList.length === 0 ? ( + + + + + + ) : ( + + {this.startParamsList.map((item, index) => ( + + + this.updateParamsList(index, param) + } + /> + this.removeStartParams(index)} + > + + + + + + + + + + + ))} + + )} + + + + + + + ) + } +}) diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/table-action.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/table-action.tsx new file mode 100644 index 0000000000..4920bd4e1e --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/table-action.tsx @@ -0,0 +1,309 @@ +/* + * 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 } from 'vue' +import { NSpace, NTooltip, NButton, NIcon, NPopconfirm } from 'naive-ui' +import { + DeleteOutlined, + DownloadOutlined, + FormOutlined, + InfoCircleFilled, + PlayCircleOutlined, + ClockCircleOutlined, + CopyOutlined, + FieldTimeOutlined, + ExportOutlined, + ApartmentOutlined, + UploadOutlined +} from '@vicons/antd' +import { useI18n } from 'vue-i18n' +import { IDefinitionData } from '../types' + +const props = { + row: { + type: Object as PropType + } +} + +export default defineComponent({ + name: 'TableAction', + props, + emits: [ + 'updateList', + 'startWorkflow', + 'timingWorkflow', + 'versionWorkflow', + 'deleteWorkflow', + 'releaseWorkflow', + 'copyWorkflow', + 'exportWorkflow', + 'gotoTimingManage' + ], + setup(props, ctx) { + const handleStartWorkflow = () => { + ctx.emit('startWorkflow') + } + + const handleTimingWorkflow = () => { + ctx.emit('timingWorkflow') + } + + const handleVersionWorkflow = () => { + ctx.emit('versionWorkflow') + } + + const handleDeleteWorkflow = () => { + ctx.emit('deleteWorkflow') + } + + const handleReleaseWorkflow = () => { + ctx.emit('releaseWorkflow') + } + + const handleCopyWorkflow = () => { + ctx.emit('copyWorkflow') + } + + const handleExportWorkflow = () => { + ctx.emit('exportWorkflow') + } + + const handleGotoTimingManage = () => { + ctx.emit('gotoTimingManage') + } + + return { + handleStartWorkflow, + handleTimingWorkflow, + handleVersionWorkflow, + handleDeleteWorkflow, + handleReleaseWorkflow, + handleCopyWorkflow, + handleExportWorkflow, + handleGotoTimingManage, + ...toRefs(props) + } + }, + render() { + const { t } = useI18n() + const releaseState = this.row?.releaseState + const scheduleReleaseState = this.row?.scheduleReleaseState + + return ( + + + {{ + default: () => t('project.workflow.edit'), + trigger: () => ( + + + + + + ) + }} + + + {{ + default: () => t('project.workflow.start'), + trigger: () => ( + + + + + + ) + }} + + + {{ + default: () => t('project.workflow.timing'), + trigger: () => ( + + + + + + ) + }} + + + {{ + default: () => t('project.workflow.up_line'), + trigger: () => ( + + + {releaseState === 'ONLINE' ? ( + + ) : ( + + )} + + + ) + }} + + + {{ + default: () => t('project.workflow.copy_workflow'), + trigger: () => ( + + + + + + ) + }} + + + {{ + default: () => t('project.workflow.cron_manage'), + trigger: () => ( + + + + + + ) + }} + + + {{ + default: () => t('project.workflow.delete'), + trigger: () => ( + + + {{ + default: () => t('project.workflow.delete_confirm'), + icon: () => ( + + + + ), + trigger: () => ( + + + + ) + }} + + + ) + }} + + + {{ + default: () => t('project.workflow.tree_view'), + trigger: () => ( + + + + + + ) + }} + + + {{ + default: () => t('project.workflow.export'), + trigger: () => ( + + + + + + ) + }} + + + {{ + default: () => t('project.workflow.version_info'), + trigger: () => ( + + + + + + ) + }} + + + ) + } +}) diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/timing-modal.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/timing-modal.tsx new file mode 100644 index 0000000000..d79f79d71f --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/timing-modal.tsx @@ -0,0 +1,321 @@ +/* + * 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, h, onMounted, ref } 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, + NButton, + NIcon, + NInput, + NSpace, + NRadio, + NRadioGroup, + NSelect, + NDatePicker, + NInputGroup, + NList, + NListItem, + NThing +} from 'naive-ui' +import { ArrowDownOutlined, ArrowUpOutlined } from '@vicons/antd' +import { timezoneList } from '@/utils/timezone' + +const props = { + row: { + type: Object, + default: {} + }, + show: { + type: Boolean as PropType, + default: false + }, + type: { + type: String as PropType, + default: 'create' + } +} + +export default defineComponent({ + name: 'workflowDefinitionStart', + props, + emits: ['update:show', 'update:row', 'updateList'], + setup(props, ctx) { + const parallelismRef = ref(false) + const { t } = useI18n() + const { timingState } = useForm() + const { + variables, + handleCreateTiming, + handleUpdateTiming, + getWorkerGroups, + getAlertGroups, + getEnvironmentList, + getPreviewSchedule + } = useModal(timingState, ctx) + + const hideModal = () => { + ctx.emit('update:show') + } + + const handleTiming = () => { + if (props.type === 'create') { + handleCreateTiming(props.row.code as number) + } else { + handleUpdateTiming(props.row.id) + } + } + + const generalWarningTypeListOptions = () => [ + { + value: 'NONE', + label: t('project.workflow.none_send') + }, + { + value: 'SUCCESS', + label: t('project.workflow.success_send') + }, + { + value: 'FAILURE', + label: t('project.workflow.failure_send') + }, + { + value: 'ALL', + label: t('project.workflow.all_send') + } + ] + + const generalPriorityList = () => [ + { + value: 'HIGHEST', + label: 'HIGHEST', + color: '#ff0000', + icon: ArrowUpOutlined + }, + { + value: 'HIGH', + label: 'HIGH', + color: '#ff0000', + icon: ArrowUpOutlined + }, + { + value: 'MEDIUM', + label: 'MEDIUM', + color: '#EA7D24', + icon: ArrowUpOutlined + }, + { + value: 'LOW', + label: 'LOW', + color: '#2A8734', + icon: ArrowDownOutlined + }, + { + value: 'LOWEST', + label: 'LOWEST', + color: '#2A8734', + icon: ArrowDownOutlined + } + ] + + const timezoneOptions = () => + timezoneList.map((item) => ({ label: item, value: item })) + + const renderLabel = (option: any) => { + return [ + h( + NIcon, + { + style: { + verticalAlign: 'middle', + marginRight: '4px', + marginBottom: '3px' + }, + color: option.color + }, + { + default: () => h(option.icon) + } + ), + option.label + ] + } + + const updateWorkerGroup = () => { + timingState.timingForm.environmentCode = null + } + + const handlePreview = () => { + getPreviewSchedule() + } + + onMounted(() => { + getWorkerGroups() + getAlertGroups() + getEnvironmentList() + }) + + return { + t, + parallelismRef, + hideModal, + handleTiming, + generalWarningTypeListOptions, + generalPriorityList, + timezoneOptions, + renderLabel, + updateWorkerGroup, + handlePreview, + ...toRefs(variables), + ...toRefs(timingState), + ...toRefs(props) + } + }, + + render() { + const { t } = this + if (Number(this.timingForm.warningGroupId) === 0) { + this.timingForm.warningGroupId = '' + } + + return ( + + + + + + + + + + {t('project.workflow.execute_time')} + + + + + + + + + + + {this.schedulePreviewList.map((item: string) => ( + + {item} +
+
+ ))} +
+
+
+
+ + + + + {t('project.workflow.continue')} + + {t('project.workflow.end')} + + + + + + + + + + + + + + + item.workerGroups?.includes(this.timingForm.workerGroup) + )} + v-model:value={this.timingForm.environmentCode} + /> + + + + +
+
+ ) + } +}) 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 new file mode 100644 index 0000000000..0203d9f459 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-form.ts @@ -0,0 +1,92 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { FormRules } from 'naive-ui' + +export const useForm = () => { + const { t } = useI18n() + const date = new Date() + const year = date.getFullYear() + const month = date.getMonth() + const day = date.getDate() + + const importState = reactive({ + importFormRef: ref(), + importForm: { + name: '', + file: '' + }, + importRules: { + file: { + required: true, + trigger: ['input', 'blur'], + validator() { + if (importState.importForm.name === '') { + return new Error(t('project.workflow.enter_name_tips')) + } + } + } + } as FormRules + }) + + const startState = reactive({ + startFormRef: ref(), + startForm: { + processDefinitionCode: -1, + startEndTime: [new Date(year, month, day), new Date(year, month, day)], + scheduleTime: null, + failureStrategy: 'CONTINUE', + warningType: 'NONE', + warningGroupId: null, + execType: '', + startNodeList: '', + taskDependType: 'TASK_POST', + runMode: 'RUN_MODE_SERIAL', + processInstancePriority: 'MEDIUM', + workerGroup: 'default', + environmentCode: null, + startParams: null, + expectedParallelismNumber: '', + dryRun: 0 + } + }) + + const timingState = reactive({ + timingFormRef: ref(), + timingForm: { + startEndTime: [ + new Date(year, month, day), + new Date(year + 100, month, day) + ], + crontab: '0 0 * * * ? *', + timezoneId: Intl.DateTimeFormat().resolvedOptions().timeZone, + failureStrategy: 'CONTINUE', + warningType: 'NONE', + processInstancePriority: 'MEDIUM', + warningGroupId: '', + workerGroup: 'default', + environmentCode: null + } + }) + return { + importState, + startState, + timingState + } +} 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 new file mode 100644 index 0000000000..e43234af11 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-modal.ts @@ -0,0 +1,247 @@ +/* + * 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 _ from 'lodash' +import { reactive, SetupContext } from 'vue' +import { useI18n } from 'vue-i18n' +import { useRouter } from 'vue-router' +import type { Router } from 'vue-router' +import { format } from 'date-fns' +import { importProcessDefinition } from '@/service/modules/process-definition' +import { queryAllWorkerGroups } from '@/service/modules/worker-groups' +import { queryAllEnvironmentList } from '@/service/modules/environment' +import { listAlertGroupById } from '@/service/modules/alert-group' +import { startProcessInstance } from '@/service/modules/executors' +import { + createSchedule, + updateSchedule, + previewSchedule +} from '@/service/modules/schedules' + +export function useModal( + state: any, + ctx: SetupContext<('update:show' | 'update:row' | 'updateList')[]> +) { + const { t } = useI18n() + const router: Router = useRouter() + + const variables = reactive({ + projectCode: Number(router.currentRoute.value.params.projectCode), + workerGroups: [], + alertGroups: [], + environmentList: [], + startParamsList: [] as Array<{ prop: string; value: string }>, + schedulePreviewList: [] + }) + + const resetImportForm = () => { + state.importFormRef.name = '' + state.importFormRef.file = '' + } + + const handleImportDefinition = () => { + state.importFormRef.validate(async (valid: any) => { + if (!valid) { + try { + const formData = new FormData() + formData.append('file', state.importForm.file) + const code = Number(router.currentRoute.value.params.projectCode) + await importProcessDefinition(formData, code) + window.$message.success(t('project.workflow.success')) + ctx.emit('updateList') + ctx.emit('update:show') + resetImportForm() + } catch (error: any) { + window.$message.error(error.message) + } + } + }) + } + + const handleStartDefinition = (code: number) => { + state.startFormRef.validate(async (valid: any) => { + if (!valid) { + state.startForm.processDefinitionCode = code + if (state.startForm.startEndTime) { + const start = format( + new Date(state.startForm.startEndTime[0]), + 'yyyy-MM-dd hh:mm:ss' + ) + const end = format( + new Date(state.startForm.startEndTime[1]), + 'yyyy-MM-dd hh:mm:ss' + ) + state.startForm.scheduleTime = `${start},${end}` + } + + const startParams = {} as any + for (const item of variables.startParamsList) { + if (item.value !== '') { + startParams[item.prop] = item.value + } + } + state.startForm.startParams = !_.isEmpty(startParams) + ? JSON.stringify(startParams) + : '' + + try { + await startProcessInstance(state.startForm, variables.projectCode) + window.$message.success(t('project.workflow.success')) + ctx.emit('updateList') + ctx.emit('update:show') + } catch (error: any) { + window.$message.error(error.message) + } + } + }) + } + + const handleCreateTiming = (code: number) => { + state.timingFormRef.validate(async (valid: any) => { + if (!valid) { + const data: any = getTimingData() + data.processDefinitionCode = code + + try { + await createSchedule(data, variables.projectCode) + window.$message.success(t('project.workflow.success')) + ctx.emit('updateList') + ctx.emit('update:show') + } catch (error: any) { + window.$message.error(error.message) + } + } + }) + } + + const handleUpdateTiming = (id: number) => { + state.timingFormRef.validate(async (valid: any) => { + if (!valid) { + const data: any = getTimingData() + data.id = id + + try { + await updateSchedule(data, variables.projectCode, id) + window.$message.success(t('project.workflow.success')) + ctx.emit('updateList') + ctx.emit('update:show') + } catch (error: any) { + window.$message.error(error.message) + } + } + }) + } + + const getTimingData = () => { + const start = format( + new Date(state.timingForm.startEndTime[0]), + 'yyyy-MM-dd hh:mm:ss' + ) + const end = format( + new Date(state.timingForm.startEndTime[1]), + 'yyyy-MM-dd hh:mm:ss' + ) + + const data = { + schedule: JSON.stringify({ + startTime: start, + endTime: end, + crontab: state.timingForm.crontab + }), + failureStrategy: state.timingForm.failureStrategy, + warningType: state.timingForm.warningType, + processInstancePriority: state.timingForm.processInstancePriority, + warningGroupId: + state.timingForm.warningGroupId === '' + ? 0 + : state.timingForm.warningGroupId, + workerGroup: state.timingForm.workerGroups, + environmentCode: state.timingForm.environmentCode + } + return data + } + + const getWorkerGroups = () => { + queryAllWorkerGroups().then((res: any) => { + variables.workerGroups = res.map((item: string) => ({ + label: item, + value: item + })) + }) + } + + const getEnvironmentList = () => { + queryAllEnvironmentList().then((res: any) => { + variables.environmentList = res.map((item: any) => ({ + label: item.name, + value: item.code, + workerGroups: item.workerGroups + })) + }) + } + + const getAlertGroups = () => { + listAlertGroupById().then((res: any) => { + variables.alertGroups = res.map((item: any) => ({ + label: item.groupName, + value: item.id + })) + }) + } + + const getPreviewSchedule = () => { + state.timingFormRef.validate(async (valid: any) => { + if (!valid) { + const projectCode = Number(router.currentRoute.value.params.projectCode) + + const start = format( + new Date(state.timingForm.startEndTime[0]), + 'yyyy-MM-dd hh:mm:ss' + ) + const end = format( + new Date(state.timingForm.startEndTime[1]), + 'yyyy-MM-dd hh:mm:ss' + ) + + const schedule = JSON.stringify({ + startTime: start, + endTime: end, + crontab: state.timingForm.crontab + }) + previewSchedule({ schedule }, projectCode) + .then((res: any) => { + variables.schedulePreviewList = res + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + }) + } + + return { + variables, + handleImportDefinition, + handleStartDefinition, + handleCreateTiming, + handleUpdateTiming, + getWorkerGroups, + getAlertGroups, + getEnvironmentList, + getPreviewSchedule + } +} diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-table.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-table.ts new file mode 100644 index 0000000000..1b147b2b17 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/use-table.ts @@ -0,0 +1,198 @@ +/* + * 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 { h, ref, reactive, SetupContext } from 'vue' +import { useRouter } from 'vue-router' +import { useI18n } from 'vue-i18n' +import { NSpace, NTooltip, NButton, NPopconfirm, NTag } from 'naive-ui' +import { + deleteVersion, + queryVersions, + switchVersion +} from '@/service/modules/process-definition' +import type { Router } from 'vue-router' +import type { TableColumns } from 'naive-ui/es/data-table/src/interface' +import { DeleteOutlined, ExclamationCircleOutlined } from '@vicons/antd' +import styles from '../index.module.scss' + +export function useTable( + ctx: SetupContext<('update:show' | 'update:row' | 'updateList')[]> +) { + const { t } = useI18n() + const router: Router = useRouter() + + const columns: TableColumns = [ + { + title: t('project.workflow.id'), + key: 'id', + width: 50, + render: (_row, index) => index + 1 + }, + { + title: t('project.workflow.version'), + key: 'version', + render: (_row) => { + if (_row.version === variables.row.version) { + return h( + NTag, + { type: 'success', size: 'small' }, + { + default: () => + `V${_row.version} ${t('project.workflow.current_version')}` + } + ) + } else { + return `V${_row.version}` + } + } + }, + { + title: t('project.workflow.description'), + key: 'description' + }, + { + title: t('project.workflow.create_time'), + key: 'createTime' + }, + { + title: t('project.workflow.operation'), + key: 'operation', + className: styles.operation, + render: (_row) => { + return h(NSpace, null, { + default: () => [ + h( + NPopconfirm, + { + onPositiveClick: () => { + handleSwitchVersion(_row.version) + } + }, + { + trigger: () => + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'info', + size: 'tiny', + disabled: _row.version === variables.row.version + }, + { + icon: () => h(ExclamationCircleOutlined) + } + ), + default: () => t('project.workflow.switch_version') + } + ), + default: () => t('project.workflow.confirm_switch_version') + } + ), + h( + NPopconfirm, + { + onPositiveClick: () => { + handleDeleteVersion(_row.version) + } + }, + { + trigger: () => + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'error', + size: 'tiny', + disabled: _row.version === variables.row.version + }, + { + icon: () => h(DeleteOutlined) + } + ), + default: () => t('project.workflow.delete') + } + ), + default: () => t('project.workflow.delete_confirm') + } + ) + ] + }) + } + } + ] + + const variables = reactive({ + columns, + row: {} as any, + tableData: [], + projectCode: ref(Number(router.currentRoute.value.params.projectCode)) + }) + + const getTableData = (row: any) => { + variables.row = row + const params = { + pageSize: 10, + pageNo: 1 + } + queryVersions( + { ...params }, + variables.projectCode, + variables.row.code + ).then((res: any) => { + variables.tableData = res.totalList.map((item: any) => ({ ...item })) + }) + } + + const handleSwitchVersion = (version: number) => { + switchVersion(variables.projectCode, variables.row.code, version) + .then(() => { + window.$message.success(t('project.workflow.success')) + ctx.emit('updateList') + getTableData(variables.row) + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + + const handleDeleteVersion = (version: number) => { + deleteVersion(variables.projectCode, variables.row.code, version) + .then(() => { + window.$message.success(t('project.workflow.success')) + ctx.emit('updateList') + getTableData(variables.row) + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + + return { + variables, + getTableData + } +} diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/version-modal.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/version-modal.tsx new file mode 100644 index 0000000000..31e1ae3b0d --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/version-modal.tsx @@ -0,0 +1,95 @@ +/* + * 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, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { NDataTable } from 'naive-ui' +import Modal from '@/components/modal' +import { useForm } from './use-form' +import { useModal } from './use-modal' +import { useTable } from './use-table' +import { IDefinitionData } from '../types' +import styles from '../index.module.scss' + +const props = { + show: { + type: Boolean as PropType, + default: false + }, + row: { + type: Object as PropType, + default: {} + } +} + +export default defineComponent({ + name: 'workflowDefinitionVersion', + props, + emits: ['update:show', 'update:row', 'updateList'], + setup(props, ctx) { + const { variables, getTableData } = useTable(ctx) + const { importState } = useForm() + const { handleImportDefinition } = useModal(importState, ctx) + const hideModal = () => { + ctx.emit('update:show') + } + + const handleImport = () => { + handleImportDefinition() + } + + const customRequest = ({ file }: any) => { + importState.importForm.name = file.name + importState.importForm.file = file.file + } + + watch( + () => props.row.code, + () => { + getTableData(props.row) + } + ) + + return { + hideModal, + handleImport, + customRequest, + ...toRefs(variables) + } + }, + + render() { + const { t } = useI18n() + + return ( + + + + ) + } +}) 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 new file mode 100644 index 0000000000..c14e4d90e7 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.module.scss @@ -0,0 +1,88 @@ +/* + * 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. + */ + + .content { + width: 100%; + + .card { + margin-bottom: 8px; + } + + .header { + display: flex; + justify-content: space-between; + align-items: center; + margin: 10px 0; + .right { + > .search { + .list { + float: right; + margin: 3px 0 3px 4px; + } + } + } + } +} + +.table { + table { + width: 100%; + tr { + height: 40px; + font-size: 12px; + th, + td { + &:nth-child(1) { + width: 50px; + text-align: center; + } + } + th { + &:nth-child(1) { + width: 60px; + text-align: center; + } + > span { + font-size: 12px; + color: #555; + } + } + } + } +} + +.pagination { + display: flex; + justify-content: center; + align-items: center; + margin-top: 20px; +} + +.operation { + > div { + > div { + margin-right: 5px !important; + } + } +} + +.startup { + align-items: center; + > div:first-child { + width: 86%; + } +} \ No newline at end of file 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 5b06713a54..3bcc8f3225 100644 --- a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx @@ -15,11 +15,139 @@ * limitations under the License. */ -import { defineComponent } from 'vue' +import Card from '@/components/card' +import { SearchOutlined } from '@vicons/antd' +import { + NButton, + NDataTable, + NIcon, + NInput, + NPagination, + NSpace +} from 'naive-ui' +import { defineComponent, onMounted, toRefs } from 'vue' +import { useI18n } from 'vue-i18n' +import { useTable } from './use-table' +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 styles from './index.module.scss' export default defineComponent({ name: 'WorkflowDefinitionList', setup() { - return () =>
WorkflowDefinitionList
+ const { variables, getTableData } = useTable() + + const requestData = () => { + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal + }) + } + + const handleUpdateList = () => { + requestData() + } + + const handleSearch = () => { + variables.page = 1 + requestData() + } + + const handleChangePageSize = () => { + variables.page = 1 + requestData() + } + + onMounted(() => { + requestData() + }) + + return { + requestData, + handleSearch, + handleUpdateList, + handleChangePageSize, + ...toRefs(variables) + } + }, + render() { + const { t } = useI18n() + + return ( +
+ +
+ + + {t('project.workflow.create_workflow')} + + (this.showRef = true)}> + {t('project.workflow.import_workflow')} + + +
+
+
+ + + + + +
+
+ +
+
+
+
+
+ + +
+ +
+
+ + + + +
+ ) } }) diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/index.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/index.tsx new file mode 100644 index 0000000000..1a436956d9 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/index.tsx @@ -0,0 +1,113 @@ +/* + * 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 Card from '@/components/card' +import { ArrowLeftOutlined } from '@vicons/antd' +import { NButton, NDataTable, NIcon, NPagination } from 'naive-ui' +import { defineComponent, onMounted, toRefs } from 'vue' +import { useI18n } from 'vue-i18n' +import { useRouter } from 'vue-router' +import type { Router } from 'vue-router' +import { useTable } from './use-table' +import TimingModal from '../components/timing-modal' +import styles from '../index.module.scss' + +export default defineComponent({ + name: 'WorkflowDefinitionTiming', + setup() { + const { variables, getTableData } = useTable() + + const requestData = () => { + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal + }) + } + + const handleUpdateList = () => { + requestData() + } + + const handleSearch = () => { + variables.page = 1 + requestData() + } + + const handleChangePageSize = () => { + variables.page = 1 + requestData() + } + + onMounted(() => { + requestData() + }) + + return { + requestData, + handleSearch, + handleUpdateList, + handleChangePageSize, + ...toRefs(variables) + } + }, + render() { + const { t } = useI18n() + const router: Router = useRouter() + + return ( +
+ +
+ router.go(-1)}> + + + + +
+
+ + +
+ +
+
+ +
+ ) + } +}) diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/types.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/types.ts new file mode 100644 index 0000000000..cc7f0e769f --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/types.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +export interface ISearchParam { + pageSize: number + pageNo: number + searchVal: string | undefined +} diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/use-table.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/use-table.ts new file mode 100644 index 0000000000..b9061942cf --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/timing/use-table.ts @@ -0,0 +1,245 @@ +/* + * 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 { h, ref, reactive } from 'vue' +import { useI18n } from 'vue-i18n' +import { useRouter } from 'vue-router' +import { NSpace, NTooltip, NButton, NPopconfirm, NEllipsis } from 'naive-ui' +import { + deleteScheduleById, + offline, + online, + queryScheduleListPaging +} from '@/service/modules/schedules' +import { + ArrowDownOutlined, + ArrowUpOutlined, + DeleteOutlined, + EditOutlined +} from '@vicons/antd' +import type { Router } from 'vue-router' +import type { TableColumns } from 'naive-ui/es/data-table/src/interface' +import { ISearchParam } from './types' +import styles from '../index.module.scss' + +export function useTable() { + const { t } = useI18n() + const router: Router = useRouter() + + const columns: TableColumns = [ + { + title: t('project.workflow.id'), + key: 'id', + width: 50, + render: (_row, index) => index + 1 + }, + { + title: t('project.workflow.workflow_name'), + key: 'processDefinitionName', + width: 200, + render: (_row) => + h( + NEllipsis, + { style: 'max-width: 200px' }, + { + default: () => _row.processDefinitionName + } + ) + }, + { + title: t('project.workflow.start_time'), + key: 'startTime' + }, + { + title: t('project.workflow.end_time'), + key: 'endTime' + }, + { + title: t('project.workflow.crontab'), + key: 'crontab' + }, + { + title: t('project.workflow.failure_strategy'), + key: 'failureStrategy' + }, + { + title: t('project.workflow.status'), + key: 'releaseState', + render: (_row) => + _row.releaseState === 'ONLINE' + ? t('project.workflow.up_line') + : t('project.workflow.down_line') + }, + { + title: t('project.workflow.create_time'), + key: 'createTime' + }, + { + title: t('project.workflow.update_time'), + key: 'updateTime' + }, + { + title: t('project.workflow.operation'), + key: 'operation', + fixed: 'right', + className: styles.operation, + render: (row) => { + return h(NSpace, null, { + default: () => [ + h( + NButton, + { + circle: true, + type: 'info', + size: 'tiny', + disabled: row.releaseState === 'ONLINE', + onClick: () => { + handleEdit(row) + } + }, + { + icon: () => h(EditOutlined) + } + ), + h( + NButton, + { + circle: true, + type: row.releaseState === 'ONLINE' ? 'error' : 'warning', + size: 'tiny', + onClick: () => { + handleReleaseState(row) + } + }, + { + icon: () => + h( + row.releaseState === 'ONLINE' + ? ArrowDownOutlined + : ArrowUpOutlined + ) + } + ), + h( + NPopconfirm, + { + onPositiveClick: () => { + handleDelete(row.id) + } + }, + { + trigger: () => + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'error', + size: 'tiny' + }, + { + icon: () => h(DeleteOutlined) + } + ), + default: () => t('project.workflow.delete') + } + ), + default: () => t('project.workflow.delete_confirm') + } + ) + ] + }) + } + } + ] + + const handleEdit = (row: any) => { + variables.showRef = true + variables.row = row + } + + const variables = reactive({ + columns, + row: {}, + tableData: [], + projectCode: ref(Number(router.currentRoute.value.params.projectCode)), + page: ref(1), + pageSize: ref(10), + searchVal: ref(), + totalPage: ref(1), + showRef: ref(false) + }) + + const getTableData = (params: ISearchParam) => { + const definitionCode = Number( + router.currentRoute.value.params.definitionCode + ) + queryScheduleListPaging( + { ...params, processDefinitionCode: definitionCode }, + variables.projectCode + ).then((res: any) => { + variables.totalPage = res.totalPage + variables.tableData = res.totalList.map((item: any) => { + return { ...item } + }) + }) + } + + const handleReleaseState = (row: any) => { + let handle = online + if (row.releaseState === 'ONLINE') { + handle = offline + } + + handle(variables.projectCode, row.id).then(() => { + window.$message.success(t('project.workflow.success')) + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal + }) + }) + } + + const handleDelete = (id: number) => { + /* after deleting data from the current page, you need to jump forward when the page is empty. */ + if (variables.tableData.length === 1 && variables.page > 1) { + variables.page -= 1 + } + deleteScheduleById(id, variables.projectCode) + .then(() => { + window.$message.success(t('project.workflow.success')) + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal + }) + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + + return { + variables, + getTableData + } +} diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/types.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/types.ts new file mode 100644 index 0000000000..4f1889f573 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/types.ts @@ -0,0 +1,72 @@ +/* + * 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. + */ + +export interface IDefinitionParam { + pageSize: number + pageNo: number + searchVal: string | undefined +} + +export interface IDefinitionData { + code: number + createTime: string + description: string + executionType: string + flag: 'YES' | 'NO' + globalParamList: any + globalParamMap: Object + globalParams: string + id: number + locations: any + modifyBy: string + name: string + projectCode: number + projectName: any + releaseState: string + scheduleReleaseState: any + tenantCode: any + tenantId: number + timeout: number + updateTime: string + userId: number + userName: string + version: number + warningGroupId: number +} + +export interface ICrontabData { + id: number + crontab: string + definitionDescription: string + endTime: string + environmentCode: number + failureStrategy: string + processDefinitionCode: number + processDefinitionName: string + processInstancePriority: string + projectName: string + releaseState: 'ONLINE' | 'OFFLINE' + startTime: string + timezoneId: string + createTime: string + updateTime: string + userId: 1 + userName: string + warningGroupId: number + warningType: string + workerGroup: string +} 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 new file mode 100644 index 0000000000..f2e3044d5b --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts @@ -0,0 +1,286 @@ +/* + * 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 { 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 { useAsyncState } from '@vueuse/core' +import { + batchCopyByCodes, + batchExportByCodes, + deleteByCode, + queryListPaging, + release +} from '@/service/modules/process-definition' +import TableAction from './components/table-action' + +import { IDefinitionParam } from './types' +import styles from './index.module.scss' +import { NEllipsis, NTag } from 'naive-ui' + +export function useTable() { + const { t } = useI18n() + const router: Router = useRouter() + + const columns: TableColumns = [ + { + title: t('project.workflow.id'), + key: 'id', + width: 50, + render: (_row, index) => index + 1 + }, + { + title: t('project.workflow.workflow_name'), + key: 'name', + width: 200, + render: (_row) => + h( + NEllipsis, + { style: 'max-width: 200px' }, + { + default: () => _row.name + } + ) + }, + { + title: t('project.workflow.status'), + key: 'releaseState', + render: (_row) => + _row.releaseState === 'ONLINE' + ? t('project.workflow.up_line') + : t('project.workflow.down_line') + }, + { + title: t('project.workflow.create_time'), + key: 'createTime', + width: 150 + }, + { + title: t('project.workflow.update_time'), + key: 'updateTime', + width: 150 + }, + { + title: t('project.workflow.description'), + key: 'description' + }, + { + title: t('project.workflow.create_user'), + key: 'userName' + }, + { + title: t('project.workflow.modify_user'), + key: 'modifyBy' + }, + { + title: t('project.workflow.schedule_publish_status'), + key: 'scheduleReleaseState', + render: (_row) => { + if (_row.scheduleReleaseState === 'ONLINE') { + return h( + NTag, + { type: 'success', size: 'small' }, + { + default: () => t('project.workflow.up_line') + } + ) + } else if (_row.scheduleReleaseState === 'OFFLINE') { + return h( + NTag, + { type: 'warning', size: 'small' }, + { + default: () => t('project.workflow.down_line') + } + ) + } else { + return '-' + } + } + }, + { + title: t('project.workflow.operation'), + key: 'operation', + width: 300, + fixed: 'right', + className: styles.operation, + render: (row) => + h(TableAction, { + row, + onStartWorkflow: () => startWorkflow(row), + onTimingWorkflow: () => timingWorkflow(row), + onVersionWorkflow: () => versionWorkflow(row), + onDeleteWorkflow: () => deleteWorkflow(row), + onReleaseWorkflow: () => releaseWorkflow(row), + onCopyWorkflow: () => copyWorkflow(row), + onExportWorkflow: () => exportWorkflow(row), + onGotoTimingManage: () => gotoTimingManage(row) + }) + } + ] + + const startWorkflow = (row: any) => { + variables.startShowRef = true + variables.row = row + } + + const timingWorkflow = (row: any) => { + variables.timingShowRef = true + variables.row = row + } + + const versionWorkflow = (row: any) => { + variables.versionShowRef = true + variables.row = row + } + + const deleteWorkflow = (row: any) => { + deleteByCode(variables.projectCode, row.code) + .then(() => { + window.$message.success(t('project.workflow.success')) + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal + }) + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + + const releaseWorkflow = (row: any) => { + const data = { + name: row.name, + releaseState: (row.releaseState === 'ONLINE' ? 'OFFLINE' : 'ONLINE') as + | 'OFFLINE' + | 'ONLINE' + } + release(data, variables.projectCode, row.code) + .then(() => { + window.$message.success(t('project.workflow.success')) + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal + }) + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + + const copyWorkflow = (row: any) => { + const data = { + codes: String(row.code), + targetProjectCode: variables.projectCode + } + batchCopyByCodes(data, variables.projectCode) + .then(() => { + window.$message.success(t('project.workflow.success')) + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal + }) + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + + const downloadBlob = (data: any, fileNameS = 'json') => { + if (!data) { + return + } + const blob = new Blob([data]) + const fileName = `${fileNameS}.json` + if ('download' in document.createElement('a')) { + // Not IE + const url = window.URL.createObjectURL(blob) + const link = document.createElement('a') + link.style.display = 'none' + link.href = url + link.setAttribute('download', fileName) + document.body.appendChild(link) + link.click() + document.body.removeChild(link) // remove element after downloading is complete. + window.URL.revokeObjectURL(url) // release blob object + } else { + // IE 10+ + if (window.navigator.msSaveBlob) { + window.navigator.msSaveBlob(blob, fileName) + } + } + } + + const exportWorkflow = (row: any) => { + const fileName = 'workflow_' + new Date().getTime() + + const data = { + codes: String(row.code) + } + batchExportByCodes(data, variables.projectCode) + .then((res: any) => { + downloadBlob(res, fileName) + }) + .catch((error: any) => { + window.$message.error(error.message) + }) + } + + const gotoTimingManage = (row: any) => { + router.push({ + name: 'workflow-definition-timing', + params: { projectCode: variables.projectCode, definitionCode: row.code } + }) + } + + const variables = reactive({ + columns, + row: {}, + tableData: [], + projectCode: ref(Number(router.currentRoute.value.params.projectCode)), + page: ref(1), + pageSize: ref(10), + searchVal: ref(), + totalPage: ref(1), + showRef: ref(false), + startShowRef: ref(false), + timingShowRef: ref(false), + versionShowRef: ref(false) + }) + + const getTableData = (params: IDefinitionParam) => { + const { state } = useAsyncState( + queryListPaging({ ...params }, variables.projectCode).then((res: any) => { + variables.totalPage = res.totalPage + variables.tableData = res.totalList.map((item: any) => { + return { ...item } + }) + }), + { total: 0, table: [] } + ) + return state + } + + return { + variables, + getTableData + } +}