dolphinscheduler-ui/src/views/projects/workflow/definition/components/timing-modal.tsx (468 lines of code) (raw):

/* * 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, watch, computed, getCurrentInstance } 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, NPopover } from 'naive-ui' import { Router, useRouter } from 'vue-router' import { ArrowDownOutlined, ArrowUpOutlined } from '@vicons/antd' import { timezoneList } from '@/common/timezone' import Crontab from '@/components/crontab' import { queryProjectPreferenceByProjectCode } from '@/service/modules/projects-preference' const props = { row: { type: Object, default: {} }, show: { type: Boolean as PropType<boolean>, default: false }, type: { type: String as PropType<String>, default: 'create' }, state: { type: String as PropType<String>, default: 'OFFLINE' } } export default defineComponent({ name: 'workflowDefinitionStart', props, emits: ['update:show', 'update:row', 'updateList'], setup(props, ctx) { const crontabRef = ref() const parallelismRef = ref(false) const { t } = useI18n() const router: Router = useRouter() const { timingState } = useForm() const { variables, handleCreateTiming, handleUpdateTiming, getWorkerGroups, getTenantList, getAlertGroups, getEnvironmentList, getPreviewSchedule } = useModal(timingState, ctx) const projectCode = Number(router.currentRoute.value.params.projectCode) const environmentOptions = computed(() => variables.environmentList.filter((item: any) => item.workerGroups?.includes(timingState.timingForm.workerGroup) ) ) const projectPreferences = ref({} as any) const initProjectPreferences = (projectCode: number) => { queryProjectPreferenceByProjectCode(projectCode).then((result: any) => { if (result?.preferences && result.state === 1) { projectPreferences.value = JSON.parse(result.preferences) } }) } const hideModal = () => { ctx.emit('update:show') } const handleTiming = () => { if (props.type === 'create') { handleCreateTiming(props.row.code as number) } else { handleUpdateTiming(props.row.id) } } const priorityOptions = [ { 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() } const initEnvironment = () => { timingState.timingForm.environmentCode = null variables.environmentList.forEach((item) => { if (props.row.environmentCode === item.value) { timingState.timingForm.environmentCode = item.value } }) } const initWarningGroup = () => { timingState.timingForm.warningGroupId = null variables.alertGroups.forEach((item) => { if (props.row.warningGroupId === item.value) { timingState.timingForm.warningGroupId = item.value } }) } const containValueInOptions = ( options: Array<any>, findingValue: string ): boolean => { for (const { value } of options) { if (findingValue === value) { return true } } return false } const restructureTimingForm = (timingForm: any) => { if (projectPreferences.value?.taskPriority) { timingForm.workflowInstancePriority = projectPreferences.value.taskPriority } if (projectPreferences.value?.warningType) { timingForm.warningType = projectPreferences.value.warningType } if (projectPreferences.value?.workerGroup) { if ( containValueInOptions( variables.workerGroups, projectPreferences.value.workerGroup ) ) { timingForm.workerGroup = projectPreferences.value.workerGroup } } if (projectPreferences.value?.tenant) { if ( containValueInOptions( variables.tenantList, projectPreferences.value.tenant ) ) { timingForm.tenantCode = projectPreferences.value.tenant } } if ( projectPreferences.value?.environmentCode && variables?.environmentList ) { if ( containValueInOptions( variables.environmentList, projectPreferences.value.environmentCode ) ) { timingForm.environmentCode = projectPreferences.value.environmentCode } } if (projectPreferences.value?.alertGroup && variables?.alertGroups) { if ( containValueInOptions( variables.alertGroups, projectPreferences.value.alertGroup ) ) { timingForm.warningGroupId = projectPreferences.value.alertGroup } } } const trim = getCurrentInstance()?.appContext.config.globalProperties.trim onMounted(() => { getWorkerGroups() getTenantList() getAlertGroups() getEnvironmentList() initProjectPreferences(projectCode) }) watch( () => props.row, () => { if (!props.row.crontab) { restructureTimingForm(timingState.timingForm) return } timingState.timingForm.startEndTime = [ new Date(props.row.startTime), new Date(props.row.endTime) ] timingState.timingForm.crontab = props.row.crontab timingState.timingForm.timezoneId = props.row.timezoneId timingState.timingForm.failureStrategy = props.row.failureStrategy timingState.timingForm.warningType = props.row.warningType timingState.timingForm.workflowInstancePriority = props.row.workflowInstancePriority timingState.timingForm.workerGroup = props.row.workerGroup timingState.timingForm.tenantCode = props.row.tenantCode initWarningGroup() initEnvironment() } ) return { t, crontabRef, parallelismRef, priorityOptions, environmentOptions, hideModal, handleTiming, timezoneOptions, renderLabel, updateWorkerGroup, handlePreview, ...toRefs(variables), ...toRefs(timingState), ...toRefs(props), trim } }, render() { const { t } = this return ( <Modal show={this.show} title={t('project.workflow.set_parameters_before_timing')} onCancel={this.hideModal} onConfirm={this.handleTiming} confirmLoading={this.saving} confirmDisabled={this.$props.state === 'ONLINE'} > <NForm ref='timingFormRef' rules={this.rules} disabled={this.$props.state === 'ONLINE'} > <NFormItem label={t('project.workflow.start_and_stop_time')} path='startEndTime' > <NDatePicker type='datetimerange' clearable v-model:value={this.timingForm.startEndTime} /> </NFormItem> <NFormItem label={t('project.workflow.timing')} path='crontab'> <NInputGroup> <NPopover trigger='click' showArrow={false} placement='bottom' style={{ width: '500px' }} > {{ trigger: () => ( <NInput allowInput={this.trim} style={{ width: '80%' }} readonly={true} v-model:value={this.timingForm.crontab} ></NInput> ), default: () => ( <Crontab v-model:value={this.timingForm.crontab} /> ) }} </NPopover> <NButton type='primary' ghost onClick={this.handlePreview}> {t('project.workflow.execute_time')} </NButton> </NInputGroup> </NFormItem> <NFormItem label={t('project.workflow.timezone')} path='timezoneId' showFeedback={false} > <NSelect v-model:value={this.timingForm.timezoneId} options={this.timezoneOptions()} filterable /> </NFormItem> <NFormItem label=' ' showFeedback={false}> <NList> {this.schedulePreviewList.length > 0 ? ( <NListItem> <NThing description={t( 'project.workflow.next_five_execution_times' )} > {this.schedulePreviewList.map((item: string) => ( <NSpace> {item} <br /> </NSpace> ))} </NThing> </NListItem> ) : null} </NList> </NFormItem> <NFormItem label={t('project.workflow.failure_strategy')} path='failureStrategy' > <NRadioGroup v-model:value={this.timingForm.failureStrategy}> <NSpace> <NRadio value='CONTINUE'> {t('project.workflow.continue')} </NRadio> <NRadio value='END'>{t('project.workflow.end')}</NRadio> </NSpace> </NRadioGroup> </NFormItem> <NFormItem label={t('project.workflow.notification_strategy')} path='warningType' > <NSelect options={[ { 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') } ]} v-model:value={this.timingForm.warningType} /> </NFormItem> {this.timingForm.warningType !== 'NONE' && ( <NFormItem label={t('project.workflow.alarm_group')} path='warningGroupId' required > <NSelect options={this.alertGroups} placeholder={t('project.workflow.please_choose')} v-model:value={this.timingForm.warningGroupId} clearable filterable /> </NFormItem> )} <NFormItem label={t('project.workflow.workflow_priority')} path='workflowInstancePriority' > <NSelect options={this.priorityOptions} renderLabel={this.renderLabel} v-model:value={this.timingForm.workflowInstancePriority} /> </NFormItem> <NFormItem label={t('project.workflow.worker_group')} path='workerGroup' > <NSelect options={this.workerGroups} onUpdateValue={this.updateWorkerGroup} v-model:value={this.timingForm.workerGroup} filterable /> </NFormItem> <NFormItem label={t('project.workflow.tenant_code')} path='tenantCode' > <NSelect options={this.tenantList} v-model:value={this.timingForm.tenantCode} filterable /> </NFormItem> <NFormItem label={t('project.workflow.environment_name')} path='environmentCode' > <NSelect options={this.environmentOptions} v-model:value={this.timingForm.environmentCode} clearable filterable /> </NFormItem> </NForm> </Modal> ) } })