diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java index 06e2a55ccd..a4b1fb9f93 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java @@ -49,6 +49,8 @@ import static org.awaitility.Awaitility.await; class WorkflowE2ETest { private static final String project = "test-workflow-1"; + private static final String workflow = "test-workflow-1"; + private static final String user = "admin"; private static final String password = "dolphinscheduler123"; @@ -86,22 +88,23 @@ class WorkflowE2ETest { .goToNav(ProjectPage.class) .goTo(project) .goToTab(WorkflowDefinitionTab.class) - .cancelPublishAll() - .deleteAll() - ; + .delete(workflow); + new NavBarPage(browser) .goToNav(ProjectPage.class) - .delete(project) + .delete(project); + + browser.navigate().refresh(); + + new NavBarPage(browser) .goToNav(SecurityPage.class) .goToTab(TenantPage.class) - .delete(tenant) - ; + .delete(tenant); } @Test @Order(1) void testCreateWorkflow() { - final String workflow = "test-workflow-1"; WorkflowDefinitionTab workflowDefinitionPage = new ProjectPage(browser) .goTo(project) @@ -163,7 +166,6 @@ class WorkflowE2ETest { @Test @Order(30) void testRunWorkflow() { - final String workflow = "test-workflow-1"; final ProjectDetailPage projectPage = new ProjectPage(browser) .goToNav(ProjectPage.class) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java index 0f6de87b91..74aa3e96d5 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java @@ -58,7 +58,7 @@ public final class LoginPage extends NavBarPage { @SneakyThrows public NavBarPage login(String username, String password) { - new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(buttonSwitchLanguage)); + new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(buttonSwitchLanguage)); buttonSwitchLanguage().click(); @@ -66,7 +66,7 @@ public final class LoginPage extends NavBarPage { inputPassword().sendKeys(password); buttonLogin().click(); - new WebDriverWait(driver, 10) + new WebDriverWait(driver, 20) .until(ExpectedConditions.urlContains("/home")); return new NavBarPage(driver); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java index 716a2e44b9..9e2ebe803d 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java @@ -19,6 +19,9 @@ */ package org.apache.dolphinscheduler.e2e.pages.project.workflow; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + import lombok.Getter; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; @@ -30,7 +33,6 @@ import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBys; import java.util.List; -import java.util.function.Supplier; import java.util.stream.Collectors; @Getter @@ -56,6 +58,12 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe }) private WebElement buttonConfirm; + @FindBys({ + @FindBy(className = "n-dialog__action"), + @FindBy(className = "n-button--default-type"), + }) + private WebElement publishSuccessButtonCancel; + @FindBy(className = "items") private List workflowList; @@ -89,6 +97,10 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe .orElseThrow(() -> new RuntimeException("Can not find publish button in workflow definition")) .click(); + ((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm()); + + ((JavascriptExecutor) driver).executeScript("arguments[0].click();", publishSuccessButtonCancel()); + return this; } @@ -114,11 +126,31 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe for (WebElement cancelButton : cancelButtons) { cancelButton.click(); + ((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm()); } return this; } + public WorkflowDefinitionTab delete(String workflow) { + await().untilAsserted(() -> assertThat(workflowList()) + .as("Workflow list should contain newly-created workflow") + .anyMatch( + it -> it.getText().contains(workflow) + )); + + workflowList() + .stream() + .filter(it -> it.findElement(By.className("workflow-name")).getAttribute("innerText").equals(workflow)) + .flatMap(it -> it.findElements(By.className("btn-delete")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("Can not find delete button in workflow definition")) + .click(); + + return this; + } + public WorkflowDefinitionTab deleteAll() { if (workflowList().isEmpty()) { return this; diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts b/dolphinscheduler-ui/src/locales/en_US/project.ts index cff8a39789..c3cbfd0972 100644 --- a/dolphinscheduler-ui/src/locales/en_US/project.ts +++ b/dolphinscheduler-ui/src/locales/en_US/project.ts @@ -75,6 +75,8 @@ export default { modify_user: 'Modify User', operation: 'Operation', edit: 'Edit', + confirm: 'Confirm', + cancel: 'Cancel', start: 'Start', timing: 'Timing', timezone: 'Timezone', @@ -226,7 +228,10 @@ export default { workflow_relation_no_data_result_desc: 'There is not any workflows. Please create a workflow, and then visit this page again.', ready_to_block: 'Ready to block', - block: 'Block' + block: 'Block', + want_to_set_timing: 'Would you like to set the workflow timing?', + confirm_to_online: 'Confirm to make the workflow online?', + confirm_to_offline: 'Confirm to make the workflow offline?', }, task: { on_line: 'Online', diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts b/dolphinscheduler-ui/src/locales/zh_CN/project.ts index edc3d98943..fca300a903 100644 --- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts +++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts @@ -226,7 +226,10 @@ export default { workflow_relation_no_data_result_desc: '目前没有任何工作流,请先创建工作流,再访问该页面', ready_to_block: '准备锁定', - block: '锁定' + block: '锁定', + want_to_set_timing: '现在想去配置该工作流定时?', + confirm_to_online: '是否确定上线该工作流?', + confirm_to_offline: '是否确定下线该工作流?', }, task: { on_line: '线上', diff --git a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx index 6ad3d488e8..332ad4d7e9 100644 --- a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx +++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx @@ -189,16 +189,25 @@ export default defineComponent({ type={releaseState === 'ONLINE' ? 'warning' : 'error'} tag='div' circle - onClick={this.handleReleaseWorkflow} class='btn-publish' > - - {releaseState === 'ONLINE' ? ( - - ) : ( - - )} - + + {{ + default: () => + releaseState === 'ONLINE' + ? t('project.workflow.confirm_to_offline') + : t('project.workflow.confirm_to_online'), + trigger: () => ( + + {releaseState === 'ONLINE' ? ( + + ) : ( + + )} + + ) + }} + ) }} diff --git a/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx b/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx index b0b6c51035..6f0ee90687 100644 --- a/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx +++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx @@ -23,7 +23,8 @@ import { NPagination, NSpace, NTooltip, - NPopconfirm + NPopconfirm, + NModal } from 'naive-ui' import { defineComponent, @@ -59,7 +60,8 @@ export default defineComponent({ getTableData, batchDeleteWorkflow, batchExportWorkflow, - batchCopyWorkflow + batchCopyWorkflow, + gotoTimingManage } = useTable() const requestData = () => { @@ -79,6 +81,10 @@ export default defineComponent({ requestData() } + const confirmToSetWorkflowTiming = () => { + gotoTimingManage(variables.row) + } + const handleSearch = () => { variables.page = 1 requestData() @@ -136,6 +142,7 @@ export default defineComponent({ batchExportWorkflow, batchCopyWorkflow, handleCopyUpdateList, + confirmToSetWorkflowTiming, ...toRefs(variables), uiSettingStore, trim @@ -300,6 +307,16 @@ export default defineComponent({ v-model:show={this.copyShowRef} onUpdateList={this.handleCopyUpdateList} /> + ) } diff --git a/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts b/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts index d46a3e8751..a339e20e46 100644 --- a/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts +++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts @@ -75,6 +75,104 @@ export function useTable() { ]) } + const createTimingListTableColumns = (variables: any) => { + variables.columns = [ + { + title: '#', + key: 'id', + ...COLUMN_WIDTH_CONFIG['index'], + render: (row: any, index: number) => index + 1 + }, + { + title: t('project.workflow.start_time'), + key: 'startTime', + ...COLUMN_WIDTH_CONFIG['timeZone'], + render: (row: any) => renderTime(row.startTime, row.timezoneId) + }, + { + title: t('project.workflow.end_time'), + key: 'endTime', + ...COLUMN_WIDTH_CONFIG['timeZone'], + render: (row: any) => renderTime(row.endTime, row.timezoneId) + }, + { + title: t('project.workflow.crontab'), + key: 'crontab', + width: 140 + }, + { + title: t('project.workflow.status'), + key: 'releaseState', + ...COLUMN_WIDTH_CONFIG['state'], + render: (row: any) => { + if (row.releaseState === 'ONLINE') { + return h( + NTag, + { type: 'success', size: 'small' }, + { + default: () => t('project.workflow.up_line') + } + ) + } else { + return h( + NTag, + { type: 'warning', size: 'small' }, + { + default: () => t('project.workflow.down_line') + } + ) + } + } + }, + { + title: t('project.workflow.operation'), + key: 'operation', + ...COLUMN_WIDTH_CONFIG['operation'](3), + render: (row: any) => { + return h(NSpace, null, { + default: () => [ + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: + row.releaseState === 'ONLINE' ? 'error' : 'warning', + size: 'small', + onClick: () => { + handleReleaseState(row) + } + }, + { + icon: () => + h( + row.releaseState === 'ONLINE' + ? ArrowDownOutlined + : ArrowUpOutlined + ) + } + ), + default: () => + row.releaseState === 'ONLINE' + ? t('project.workflow.down_line') + : t('project.workflow.up_line') + } + ), + ] + }) + } + } + ] + if (variables.tableWidth) { + variables.tableWidth = calculateTableWidth(variables.columns) + } + } + + const createColumns = (variables: any) => { variables.columns = [ { @@ -326,6 +424,7 @@ export function useTable() { return { variables, createColumns, + createTimingListTableColumns, getTableData } } diff --git a/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts b/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts index d8e57139c3..fb2d836f5e 100644 --- a/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts +++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts @@ -63,7 +63,8 @@ export function useTable() { timingShowRef: ref(false), versionShowRef: ref(false), copyShowRef: ref(false), - loadingRef: ref(false) + loadingRef: ref(false), + setTimingDialogShowRef: ref(false) }) const createColumns = (variables: any) => { @@ -351,8 +352,14 @@ export function useTable() { | 'OFFLINE' | 'ONLINE' } + release(data, variables.projectCode, row.code).then(() => { - window.$message.success(t('project.workflow.success')) + if (data.releaseState === 'ONLINE') { + variables.setTimingDialogShowRef = true + variables.row = row + } else { + window.$message.success(t('project.workflow.success')) + } getTableData({ pageSize: variables.pageSize, pageNo: variables.page, @@ -448,6 +455,7 @@ export function useTable() { getTableData, batchDeleteWorkflow, batchExportWorkflow, - batchCopyWorkflow + batchCopyWorkflow, + gotoTimingManage } }