[Improvement-14456][UI] When making the process online the system should remind user to take care of its offline timing. (#14460)
This commit is contained in:
parent
a1bf597d0a
commit
92d2b8e33f
|
|
@ -49,6 +49,8 @@ import static org.awaitility.Awaitility.await;
|
||||||
class WorkflowE2ETest {
|
class WorkflowE2ETest {
|
||||||
private static final String project = "test-workflow-1";
|
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 user = "admin";
|
||||||
|
|
||||||
private static final String password = "dolphinscheduler123";
|
private static final String password = "dolphinscheduler123";
|
||||||
|
|
@ -86,22 +88,23 @@ class WorkflowE2ETest {
|
||||||
.goToNav(ProjectPage.class)
|
.goToNav(ProjectPage.class)
|
||||||
.goTo(project)
|
.goTo(project)
|
||||||
.goToTab(WorkflowDefinitionTab.class)
|
.goToTab(WorkflowDefinitionTab.class)
|
||||||
.cancelPublishAll()
|
.delete(workflow);
|
||||||
.deleteAll()
|
|
||||||
;
|
|
||||||
new NavBarPage(browser)
|
new NavBarPage(browser)
|
||||||
.goToNav(ProjectPage.class)
|
.goToNav(ProjectPage.class)
|
||||||
.delete(project)
|
.delete(project);
|
||||||
|
|
||||||
|
browser.navigate().refresh();
|
||||||
|
|
||||||
|
new NavBarPage(browser)
|
||||||
.goToNav(SecurityPage.class)
|
.goToNav(SecurityPage.class)
|
||||||
.goToTab(TenantPage.class)
|
.goToTab(TenantPage.class)
|
||||||
.delete(tenant)
|
.delete(tenant);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(1)
|
@Order(1)
|
||||||
void testCreateWorkflow() {
|
void testCreateWorkflow() {
|
||||||
final String workflow = "test-workflow-1";
|
|
||||||
WorkflowDefinitionTab workflowDefinitionPage =
|
WorkflowDefinitionTab workflowDefinitionPage =
|
||||||
new ProjectPage(browser)
|
new ProjectPage(browser)
|
||||||
.goTo(project)
|
.goTo(project)
|
||||||
|
|
@ -163,7 +166,6 @@ class WorkflowE2ETest {
|
||||||
@Test
|
@Test
|
||||||
@Order(30)
|
@Order(30)
|
||||||
void testRunWorkflow() {
|
void testRunWorkflow() {
|
||||||
final String workflow = "test-workflow-1";
|
|
||||||
final ProjectDetailPage projectPage =
|
final ProjectDetailPage projectPage =
|
||||||
new ProjectPage(browser)
|
new ProjectPage(browser)
|
||||||
.goToNav(ProjectPage.class)
|
.goToNav(ProjectPage.class)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ public final class LoginPage extends NavBarPage {
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public NavBarPage login(String username, String password) {
|
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();
|
buttonSwitchLanguage().click();
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ public final class LoginPage extends NavBarPage {
|
||||||
inputPassword().sendKeys(password);
|
inputPassword().sendKeys(password);
|
||||||
buttonLogin().click();
|
buttonLogin().click();
|
||||||
|
|
||||||
new WebDriverWait(driver, 10)
|
new WebDriverWait(driver, 20)
|
||||||
.until(ExpectedConditions.urlContains("/home"));
|
.until(ExpectedConditions.urlContains("/home"));
|
||||||
|
|
||||||
return new NavBarPage(driver);
|
return new NavBarPage(driver);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.dolphinscheduler.e2e.pages.project.workflow;
|
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 lombok.Getter;
|
||||||
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
|
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
|
||||||
import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage;
|
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 org.openqa.selenium.support.FindBys;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|
@ -56,6 +58,12 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe
|
||||||
})
|
})
|
||||||
private WebElement buttonConfirm;
|
private WebElement buttonConfirm;
|
||||||
|
|
||||||
|
@FindBys({
|
||||||
|
@FindBy(className = "n-dialog__action"),
|
||||||
|
@FindBy(className = "n-button--default-type"),
|
||||||
|
})
|
||||||
|
private WebElement publishSuccessButtonCancel;
|
||||||
|
|
||||||
@FindBy(className = "items")
|
@FindBy(className = "items")
|
||||||
private List<WebElement> workflowList;
|
private List<WebElement> workflowList;
|
||||||
|
|
||||||
|
|
@ -89,6 +97,10 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe
|
||||||
.orElseThrow(() -> new RuntimeException("Can not find publish button in workflow definition"))
|
.orElseThrow(() -> new RuntimeException("Can not find publish button in workflow definition"))
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
|
((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm());
|
||||||
|
|
||||||
|
((JavascriptExecutor) driver).executeScript("arguments[0].click();", publishSuccessButtonCancel());
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,11 +126,31 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe
|
||||||
|
|
||||||
for (WebElement cancelButton : cancelButtons) {
|
for (WebElement cancelButton : cancelButtons) {
|
||||||
cancelButton.click();
|
cancelButton.click();
|
||||||
|
((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
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() {
|
public WorkflowDefinitionTab deleteAll() {
|
||||||
if (workflowList().isEmpty()) {
|
if (workflowList().isEmpty()) {
|
||||||
return this;
|
return this;
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,8 @@ export default {
|
||||||
modify_user: 'Modify User',
|
modify_user: 'Modify User',
|
||||||
operation: 'Operation',
|
operation: 'Operation',
|
||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
|
confirm: 'Confirm',
|
||||||
|
cancel: 'Cancel',
|
||||||
start: 'Start',
|
start: 'Start',
|
||||||
timing: 'Timing',
|
timing: 'Timing',
|
||||||
timezone: 'Timezone',
|
timezone: 'Timezone',
|
||||||
|
|
@ -226,7 +228,10 @@ export default {
|
||||||
workflow_relation_no_data_result_desc:
|
workflow_relation_no_data_result_desc:
|
||||||
'There is not any workflows. Please create a workflow, and then visit this page again.',
|
'There is not any workflows. Please create a workflow, and then visit this page again.',
|
||||||
ready_to_block: 'Ready to block',
|
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: {
|
task: {
|
||||||
on_line: 'Online',
|
on_line: 'Online',
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,10 @@ export default {
|
||||||
workflow_relation_no_data_result_desc:
|
workflow_relation_no_data_result_desc:
|
||||||
'目前没有任何工作流,请先创建工作流,再访问该页面',
|
'目前没有任何工作流,请先创建工作流,再访问该页面',
|
||||||
ready_to_block: '准备锁定',
|
ready_to_block: '准备锁定',
|
||||||
block: '锁定'
|
block: '锁定',
|
||||||
|
want_to_set_timing: '现在想去配置该工作流定时?',
|
||||||
|
confirm_to_online: '是否确定上线该工作流?',
|
||||||
|
confirm_to_offline: '是否确定下线该工作流?',
|
||||||
},
|
},
|
||||||
task: {
|
task: {
|
||||||
on_line: '线上',
|
on_line: '线上',
|
||||||
|
|
|
||||||
|
|
@ -189,16 +189,25 @@ export default defineComponent({
|
||||||
type={releaseState === 'ONLINE' ? 'warning' : 'error'}
|
type={releaseState === 'ONLINE' ? 'warning' : 'error'}
|
||||||
tag='div'
|
tag='div'
|
||||||
circle
|
circle
|
||||||
onClick={this.handleReleaseWorkflow}
|
|
||||||
class='btn-publish'
|
class='btn-publish'
|
||||||
>
|
>
|
||||||
<NIcon>
|
<NPopconfirm onPositiveClick={this.handleReleaseWorkflow}>
|
||||||
{releaseState === 'ONLINE' ? (
|
{{
|
||||||
<DownloadOutlined />
|
default: () =>
|
||||||
) : (
|
releaseState === 'ONLINE'
|
||||||
<UploadOutlined />
|
? t('project.workflow.confirm_to_offline')
|
||||||
)}
|
: t('project.workflow.confirm_to_online'),
|
||||||
</NIcon>
|
trigger: () => (
|
||||||
|
<NIcon>
|
||||||
|
{releaseState === 'ONLINE' ? (
|
||||||
|
<DownloadOutlined />
|
||||||
|
) : (
|
||||||
|
<UploadOutlined />
|
||||||
|
)}
|
||||||
|
</NIcon>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</NPopconfirm>
|
||||||
</NButton>
|
</NButton>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ import {
|
||||||
NPagination,
|
NPagination,
|
||||||
NSpace,
|
NSpace,
|
||||||
NTooltip,
|
NTooltip,
|
||||||
NPopconfirm
|
NPopconfirm,
|
||||||
|
NModal
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
|
|
@ -59,7 +60,8 @@ export default defineComponent({
|
||||||
getTableData,
|
getTableData,
|
||||||
batchDeleteWorkflow,
|
batchDeleteWorkflow,
|
||||||
batchExportWorkflow,
|
batchExportWorkflow,
|
||||||
batchCopyWorkflow
|
batchCopyWorkflow,
|
||||||
|
gotoTimingManage
|
||||||
} = useTable()
|
} = useTable()
|
||||||
|
|
||||||
const requestData = () => {
|
const requestData = () => {
|
||||||
|
|
@ -79,6 +81,10 @@ export default defineComponent({
|
||||||
requestData()
|
requestData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const confirmToSetWorkflowTiming = () => {
|
||||||
|
gotoTimingManage(variables.row)
|
||||||
|
}
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
variables.page = 1
|
variables.page = 1
|
||||||
requestData()
|
requestData()
|
||||||
|
|
@ -136,6 +142,7 @@ export default defineComponent({
|
||||||
batchExportWorkflow,
|
batchExportWorkflow,
|
||||||
batchCopyWorkflow,
|
batchCopyWorkflow,
|
||||||
handleCopyUpdateList,
|
handleCopyUpdateList,
|
||||||
|
confirmToSetWorkflowTiming,
|
||||||
...toRefs(variables),
|
...toRefs(variables),
|
||||||
uiSettingStore,
|
uiSettingStore,
|
||||||
trim
|
trim
|
||||||
|
|
@ -300,6 +307,16 @@ export default defineComponent({
|
||||||
v-model:show={this.copyShowRef}
|
v-model:show={this.copyShowRef}
|
||||||
onUpdateList={this.handleCopyUpdateList}
|
onUpdateList={this.handleCopyUpdateList}
|
||||||
/>
|
/>
|
||||||
|
<NModal
|
||||||
|
v-model:show={this.setTimingDialogShowRef}
|
||||||
|
preset={'dialog'}
|
||||||
|
title={t('project.workflow.success')}
|
||||||
|
content={t('project.workflow.want_to_set_timing')}
|
||||||
|
positiveText={t('project.workflow.confirm')}
|
||||||
|
negativeText={t('project.workflow.cancel')}
|
||||||
|
maskClosable={false}
|
||||||
|
onPositiveClick={this.confirmToSetWorkflowTiming}
|
||||||
|
/>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
const createColumns = (variables: any) => {
|
||||||
variables.columns = [
|
variables.columns = [
|
||||||
{
|
{
|
||||||
|
|
@ -326,6 +424,7 @@ export function useTable() {
|
||||||
return {
|
return {
|
||||||
variables,
|
variables,
|
||||||
createColumns,
|
createColumns,
|
||||||
|
createTimingListTableColumns,
|
||||||
getTableData
|
getTableData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ export function useTable() {
|
||||||
timingShowRef: ref(false),
|
timingShowRef: ref(false),
|
||||||
versionShowRef: ref(false),
|
versionShowRef: ref(false),
|
||||||
copyShowRef: ref(false),
|
copyShowRef: ref(false),
|
||||||
loadingRef: ref(false)
|
loadingRef: ref(false),
|
||||||
|
setTimingDialogShowRef: ref(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
const createColumns = (variables: any) => {
|
const createColumns = (variables: any) => {
|
||||||
|
|
@ -351,8 +352,14 @@ export function useTable() {
|
||||||
| 'OFFLINE'
|
| 'OFFLINE'
|
||||||
| 'ONLINE'
|
| 'ONLINE'
|
||||||
}
|
}
|
||||||
|
|
||||||
release(data, variables.projectCode, row.code).then(() => {
|
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({
|
getTableData({
|
||||||
pageSize: variables.pageSize,
|
pageSize: variables.pageSize,
|
||||||
pageNo: variables.page,
|
pageNo: variables.page,
|
||||||
|
|
@ -448,6 +455,7 @@ export function useTable() {
|
||||||
getTableData,
|
getTableData,
|
||||||
batchDeleteWorkflow,
|
batchDeleteWorkflow,
|
||||||
batchExportWorkflow,
|
batchExportWorkflow,
|
||||||
batchCopyWorkflow
|
batchCopyWorkflow,
|
||||||
|
gotoTimingManage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue