Browse Source

[Improvement][Monitor] Show master && worker Busy Or Normal Status and Show Commands table list (#15978)

* update

* test

* add monitor enhance ui

* update

* update

* update doc

* fix spotless

* update

* update

* Update dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/CommandMapper.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* update

* fix spotless

* update

---------

Co-authored-by: Wenjun Ruan <wenjun@apache.org>
3.2.2-release-bak
旺阳 6 months ago committed by GitHub
parent
commit
0e5cb664bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 21
      docs/docs/en/guide/monitor.md
  2. 21
      docs/docs/zh/guide/monitor.md
  3. BIN
      docs/img/new_ui/dev/monitor/alert-server.png
  4. BIN
      docs/img/new_ui/dev/monitor/audit-log.jpg
  5. BIN
      docs/img/new_ui/dev/monitor/audit-log.png
  6. BIN
      docs/img/new_ui/dev/monitor/command-list.png
  7. BIN
      docs/img/new_ui/dev/monitor/failure-command-list.png
  8. BIN
      docs/img/new_ui/dev/monitor/master.png
  9. BIN
      docs/img/new_ui/dev/monitor/statistics.png
  10. BIN
      docs/img/new_ui/dev/monitor/worker.png
  11. 54
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java
  12. 32
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/MonitorController.java
  13. 6
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/DataAnalysisService.java
  14. 20
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/MonitorService.java
  15. 66
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/DataAnalysisServiceImpl.java
  16. 5
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java
  17. 47
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/MonitorServiceImpl.java
  18. 25
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/MonitorControllerTest.java
  19. 5
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ExecuteFunctionServiceTest.java
  20. 4
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/MonitorServiceTest.java
  21. 7
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/CommandMapper.java
  22. 7
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.java
  23. 1
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.java
  24. 16
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/CommandMapper.xml
  25. 19
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml
  26. 10
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.xml
  27. 3
      dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/CommandMapperTest.java
  28. 1
      dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/enums/RegistryNodeType.java
  29. 4
      dolphinscheduler-ui/src/layouts/content/use-dataList.ts
  30. 1
      dolphinscheduler-ui/src/locales/en_US/menu.ts
  31. 6
      dolphinscheduler-ui/src/locales/en_US/monitor.ts
  32. 1
      dolphinscheduler-ui/src/locales/zh_CN/menu.ts
  33. 6
      dolphinscheduler-ui/src/locales/zh_CN/monitor.ts
  34. 11
      dolphinscheduler-ui/src/router/modules/monitor.ts
  35. 8
      dolphinscheduler-ui/src/service/modules/monitor/index.ts
  36. 31
      dolphinscheduler-ui/src/service/modules/monitor/types.ts
  37. 18
      dolphinscheduler-ui/src/service/modules/projects-analysis/index.ts
  38. 9
      dolphinscheduler-ui/src/service/modules/projects-analysis/types.ts
  39. 43
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.module.scss
  40. 189
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.tsx
  41. 80
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/node-modal.tsx
  42. 38
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/use-server-node.ts
  43. 24
      dolphinscheduler-ui/src/views/monitor/servers/master/index.tsx
  44. 4
      dolphinscheduler-ui/src/views/monitor/servers/master/use-master.ts
  45. 63
      dolphinscheduler-ui/src/views/monitor/servers/worker/index.tsx
  46. 4
      dolphinscheduler-ui/src/views/monitor/servers/worker/use-worker.ts
  47. 76
      dolphinscheduler-ui/src/views/monitor/statistics/statistics/index.tsx
  48. 233
      dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-command-table.tsx
  49. 237
      dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-error-command-table.tsx

21
docs/docs/en/guide/monitor.md

@ -16,6 +16,12 @@
![worker](../../../img/new_ui/dev/monitor/worker.png)
### Alert Server
- Mainly related to alert server information.
![alert-server](../../../img/new_ui/dev/monitor/alert-server.png)
### Database
- Mainly the health status of the DB.
@ -26,18 +32,17 @@
### Statistics
![statistics](../../../img/new_ui/dev/monitor/statistics.png)
![Command Statistics List](../../../img/new_ui/dev/monitor/command-list.png)
Shows the command list in the system. Data is from the `t_ds_command` table.
![Failure Command Statistics List](../../../img/new_ui/dev/monitor/failure-command-list.png)
| **Parameter** | **Description** |
|----------------------------------------|----------------------------------------------------|
| Number of commands wait to be executed | Statistics of the `t_ds_command` table data. |
| The number of failed commands | Statistics of the `t_ds_error_command` table data. |
| Number of tasks wait to run | Count the data of `task_queue` in the ZooKeeper. |
| Number of tasks wait to be killed | Count the data of `task_kill` in the ZooKeeper. |
Shows the failure command list in the system. Data is from the `t_ds_error_command` table.
### Audit Log
The audit log provides information about who accesses the system and the operations made to the system and record related
time, which strengthen the security of the system and maintenance.
![audit-log](../../../img/new_ui/dev/monitor/audit-log.jpg)
![audit-log](../../../img/new_ui/dev/monitor/audit-log.png)

21
docs/docs/zh/guide/monitor.md

@ -16,6 +16,12 @@
![worker](../../../img/new_ui/dev/monitor/worker.png)
### Alert Server
- 主要是 alert server 的相关信息。
![alert-server](../../../img/new_ui/dev/monitor/alert-server.png)
### Database
- 主要是 DB 的健康状况
@ -26,15 +32,16 @@
### Statistics
![statistics](../../../img/new_ui/dev/monitor/statistics.png)
![Command Statistics List](../../../img/new_ui/dev/monitor/command-list.png)
展示系统中的命令列表,数据来自`t_ds_command`表。
![Failure Command Statistics List](../../../img/new_ui/dev/monitor/failure-command-list.png)
- 待执行命令数:统计 t_ds_command 表的数据
- 执行失败的命令数:统计 t_ds_error_command 表的数据
- 待运行任务数:统计 Zookeeper 中 task_queue 的数据
- 待杀死任务数:统计 Zookeeper 中 task_kill 的数据
展示系统中的失败命令列表,数据来自`t_ds_error_command`表。
### 审计日志
审计日志的记录提供了有关谁访问了系统,以及他或她在给定时间段内执行了哪些操作的信息,对于维护安全都很有用。
审计日志的记录提供了有关谁访问了系统,以及他或她在给定时间段内执行了哪些操作的信息,对于维护安全都很有用。
![audit-log](../../../img/new_ui/dev/monitor/audit-log.jpg)
![audit-log](../../../img/new_ui/dev/monitor/audit-log.png)

BIN
docs/img/new_ui/dev/monitor/alert-server.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
docs/img/new_ui/dev/monitor/audit-log.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

BIN
docs/img/new_ui/dev/monitor/audit-log.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
docs/img/new_ui/dev/monitor/command-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
docs/img/new_ui/dev/monitor/failure-command-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
docs/img/new_ui/dev/monitor/master.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 134 KiB

BIN
docs/img/new_ui/dev/monitor/statistics.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/img/new_ui/dev/monitor/worker.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 139 KiB

54
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java

@ -20,17 +20,21 @@ package org.apache.dolphinscheduler.api.controller;
import static org.apache.dolphinscheduler.api.enums.Status.COMMAND_STATE_COUNT_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.COUNT_PROCESS_DEFINITION_USER_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.COUNT_PROCESS_INSTANCE_STATE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.LIST_PAGING_ALERT_GROUP_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUEUE_COUNT_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.TASK_INSTANCE_STATE_COUNT_ERROR;
import org.apache.dolphinscheduler.api.dto.CommandStateCount;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.DataAnalysisService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.dao.entity.Command;
import org.apache.dolphinscheduler.dao.entity.ErrorCommand;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.List;
@ -148,4 +152,54 @@ public class DataAnalysisController extends BaseController {
Map<String, Integer> stringIntegerMap = dataAnalysisService.countQueueState(loginUser);
return Result.success(stringIntegerMap);
}
/**
* command queue
*
* @param loginUser login user
* @return queue state count
*/
@Operation(summary = "listPendingCommands", description = "LIST_PENDING_COMMANDS")
@Parameters({
@Parameter(name = "searchVal", description = "SEARCH_VAL", schema = @Schema(implementation = String.class)),
@Parameter(name = "pageNo", description = "PAGE_NO", required = true, schema = @Schema(implementation = int.class, example = "1")),
@Parameter(name = "pageSize", description = "PAGE_SIZE", required = true, schema = @Schema(implementation = int.class, example = "20"))
})
@GetMapping("/listCommand")
@ResponseStatus(HttpStatus.OK)
@ApiException(LIST_PAGING_ALERT_GROUP_ERROR)
public Result<PageInfo<Command>> listPaging(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "projectCode", required = false) Long projectCode,
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize) {
checkPageParams(pageNo, pageSize);
PageInfo<Command> commandPageInfo =
dataAnalysisService.listPendingCommands(loginUser, projectCode, pageNo, pageSize);
return Result.success(commandPageInfo);
}
/**
* error command
*
* @param loginUser login user
* @return queue state count
*/
@Operation(summary = "listErrorCommand", description = "LIST_ERROR_COMMAND_LIST_PAGING_NOTES")
@Parameters({
@Parameter(name = "searchVal", description = "SEARCH_VAL", schema = @Schema(implementation = String.class)),
@Parameter(name = "pageNo", description = "PAGE_NO", required = true, schema = @Schema(implementation = int.class, example = "1")),
@Parameter(name = "pageSize", description = "PAGE_SIZE", required = true, schema = @Schema(implementation = int.class, example = "20"))
})
@GetMapping("/listErrorCommand")
@ResponseStatus(HttpStatus.OK)
@ApiException(LIST_PAGING_ALERT_GROUP_ERROR)
public Result<PageInfo<ErrorCommand>> listErrorCommand(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "projectCode", required = false) Long projectCode,
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize) {
checkPageParams(pageNo, pageSize);
PageInfo<ErrorCommand> errorCommandPageInfo =
dataAnalysisService.listErrorCommand(loginUser, projectCode, pageNo, pageSize);
return Result.success(errorCommandPageInfo);
}
}

32
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/MonitorController.java

@ -18,7 +18,6 @@
package org.apache.dolphinscheduler.api.controller;
import static org.apache.dolphinscheduler.api.enums.Status.LIST_MASTERS_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.LIST_WORKERS_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_DATABASE_STATE_ERROR;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
@ -26,15 +25,16 @@ import org.apache.dolphinscheduler.api.service.MonitorService;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.model.Server;
import org.apache.dolphinscheduler.common.model.WorkerServerModel;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
@ -56,35 +56,19 @@ public class MonitorController extends BaseController {
private MonitorService monitorService;
/**
* master list
* server list
*
* @param loginUser login user
* @return master list
* @return server list
*/
@Operation(summary = "listMaster", description = "MASTER_LIST_NOTES")
@GetMapping(value = "/masters")
@Operation(summary = "listServer", description = "SERVER_LIST_NOTES")
@GetMapping(value = "/{nodeType}")
@ResponseStatus(HttpStatus.OK)
@ApiException(LIST_MASTERS_ERROR)
public Result<List<Server>> listMaster(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser) {
List<Server> servers = monitorService.queryMaster(loginUser);
public Result<List<Server>> listServer(@PathVariable("nodeType") RegistryNodeType nodeType) {
List<Server> servers = monitorService.listServer(nodeType);
return Result.success(servers);
}
/**
* worker list
*
* @param loginUser login user
* @return worker information list
*/
@Operation(summary = "listWorker", description = "WORKER_LIST_NOTES")
@GetMapping(value = "/workers")
@ResponseStatus(HttpStatus.OK)
@ApiException(LIST_WORKERS_ERROR)
public Result<List<WorkerServerModel>> listWorker(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser) {
List<WorkerServerModel> workerServerModels = monitorService.queryWorker(loginUser);
return Result.success(workerServerModels);
}
/**
* query database state
*

6
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/DataAnalysisService.java

@ -21,9 +21,12 @@ import org.apache.dolphinscheduler.api.dto.CommandStateCount;
import org.apache.dolphinscheduler.api.dto.DefineUserDto;
import org.apache.dolphinscheduler.api.dto.TaskCountDto;
import org.apache.dolphinscheduler.api.dto.project.StatisticsStateRequest;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO;
import org.apache.dolphinscheduler.dao.entity.Command;
import org.apache.dolphinscheduler.dao.entity.ErrorCommand;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.List;
@ -117,4 +120,7 @@ public interface DataAnalysisService {
*/
TaskCountDto countOneTaskStates(User loginUser, Long taskCode);
PageInfo<Command> listPendingCommands(User loginUser, Long projectCode, Integer pageNo, Integer pageSize);
PageInfo<ErrorCommand> listErrorCommand(User loginUser, Long projectCode, Integer pageNo, Integer pageSize);
}

20
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/MonitorService.java

@ -18,9 +18,9 @@
package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.common.model.Server;
import org.apache.dolphinscheduler.common.model.WorkerServerModel;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import java.util.List;
@ -38,20 +38,10 @@ public interface MonitorService {
List<DatabaseMetrics> queryDatabaseState(User loginUser);
/**
* query master list
* query server list
*
* @param loginUser login user
* @return master information list
* @param nodeType RegistryNodeType
* @return server information list
*/
List<Server> queryMaster(User loginUser);
/**
* query worker list
*
* @param loginUser login user
* @return worker information list
*/
List<WorkerServerModel> queryWorker(User loginUser);
List<Server> getServerListFromRegistry(boolean isMaster);
List<Server> listServer(RegistryNodeType nodeType);
}

66
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/DataAnalysisServiceImpl.java

@ -27,14 +27,18 @@ import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.exceptions.ServiceException;
import org.apache.dolphinscheduler.api.service.DataAnalysisService;
import org.apache.dolphinscheduler.api.service.ProjectService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.enums.AuthorizationType;
import org.apache.dolphinscheduler.common.enums.CommandType;
import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.dao.entity.Command;
import org.apache.dolphinscheduler.dao.entity.CommandCount;
import org.apache.dolphinscheduler.dao.entity.ErrorCommand;
import org.apache.dolphinscheduler.dao.entity.ExecuteStatusCount;
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
import org.apache.dolphinscheduler.dao.entity.Project;
@ -71,6 +75,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
/**
@ -380,6 +386,66 @@ public class DataAnalysisServiceImpl extends BaseServiceImpl implements DataAnal
return new TaskCountDto(executeStatusCounts);
}
@Override
public PageInfo<Command> listPendingCommands(User loginUser, Long projectCode, Integer pageNo, Integer pageSize) {
Page<Command> page = new Page<>(pageNo, pageSize);
if (loginUser.getUserType().equals(UserType.ADMIN_USER)) {
IPage<Command> commandIPage = commandMapper.queryCommandPage(page);
return PageInfo.of(commandIPage);
}
List<Long> workflowDefinitionCodes = getAuthDefinitionCodes(loginUser, projectCode);
if (workflowDefinitionCodes.isEmpty()) {
return PageInfo.of(pageNo, pageSize);
}
IPage<Command> commandIPage =
commandMapper.queryCommandPageByIds(page, new ArrayList<>(workflowDefinitionCodes));
return PageInfo.of(commandIPage);
}
@Override
public PageInfo<ErrorCommand> listErrorCommand(User loginUser, Long projectCode, Integer pageNo, Integer pageSize) {
Page<ErrorCommand> page = new Page<>(pageNo, pageSize);
if (loginUser.getUserType().equals(UserType.ADMIN_USER)) {
IPage<ErrorCommand> commandIPage = errorCommandMapper.queryErrorCommandPage(page);
return PageInfo.of(commandIPage);
}
List<Long> workflowDefinitionCodes = getAuthDefinitionCodes(loginUser, projectCode);
if (workflowDefinitionCodes.isEmpty()) {
return PageInfo.of(pageNo, pageSize);
}
IPage<ErrorCommand> commandIPage =
errorCommandMapper.queryErrorCommandPageByIds(page, new ArrayList<>(workflowDefinitionCodes));
return PageInfo.of(commandIPage);
}
private List<Long> getAuthDefinitionCodes(User loginUser, Long projectCode) {
Set<Integer> projectIds = resourcePermissionCheckService
.userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS, loginUser.getId(), log);
if (CollectionUtils.isEmpty(projectIds)) {
return Collections.emptyList();
}
List<Long> projectCodes = projectMapper.selectBatchIds(projectIds)
.stream()
.map(Project::getCode)
.collect(Collectors.toList());
if (projectCode != null) {
if (!projectCodes.contains(projectCode)) {
return Collections.emptyList();
}
projectCodes = Collections.singletonList(projectCode);
}
return processDefinitionMapper.queryDefinitionCodeListByProjectCodes(projectCodes);
}
/**
* statistics the process definition quantities of a certain person
* <p>

5
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java

@ -90,6 +90,7 @@ import org.apache.dolphinscheduler.extract.master.transportor.StreamingTaskTrigg
import org.apache.dolphinscheduler.extract.master.transportor.StreamingTaskTriggerResponse;
import org.apache.dolphinscheduler.extract.master.transportor.WorkflowInstanceStateChangeEvent;
import org.apache.dolphinscheduler.plugin.task.api.TaskConstants;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import org.apache.dolphinscheduler.service.command.CommandService;
import org.apache.dolphinscheduler.service.cron.CronUtils;
import org.apache.dolphinscheduler.service.exceptions.CronParseException;
@ -289,7 +290,7 @@ public class ExecutorServiceImpl extends BaseServiceImpl implements ExecutorServ
private void checkMasterExists() {
// check master server exists
List<Server> masterServers = monitorService.getServerListFromRegistry(true);
List<Server> masterServers = monitorService.listServer(RegistryNodeType.MASTER);
// no master
if (masterServers.isEmpty()) {
@ -1142,7 +1143,7 @@ public class ExecutorServiceImpl extends BaseServiceImpl implements ExecutorServ
checkValidTenant(tenantCode);
checkMasterExists();
// todo dispatch improvement
List<Server> masterServerList = monitorService.getServerListFromRegistry(true);
List<Server> masterServerList = monitorService.listServer(RegistryNodeType.MASTER);
Server server = masterServerList.get(0);
StreamingTaskTriggerRequest taskExecuteStartMessage = new StreamingTaskTriggerRequest();

47
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/MonitorServiceImpl.java

@ -19,7 +19,6 @@ package org.apache.dolphinscheduler.api.service.impl;
import org.apache.dolphinscheduler.api.service.MonitorService;
import org.apache.dolphinscheduler.common.model.Server;
import org.apache.dolphinscheduler.common.model.WorkerServerModel;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMonitor;
@ -27,7 +26,6 @@ import org.apache.dolphinscheduler.registry.api.RegistryClient;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
@ -35,7 +33,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* monitor service impl
@ -61,48 +58,8 @@ public class MonitorServiceImpl extends BaseServiceImpl implements MonitorServic
return Lists.newArrayList(databaseMonitor.getDatabaseMetrics());
}
/**
* query master list
*
* @param loginUser login user
* @return master information list
*/
@Override
public List<Server> queryMaster(User loginUser) {
return registryClient.getServerList(RegistryNodeType.MASTER);
public List<Server> listServer(RegistryNodeType nodeType) {
return registryClient.getServerList(nodeType);
}
/**
* query worker list
*
* @param loginUser login user
* @return worker information list
*/
@Override
public List<WorkerServerModel> queryWorker(User loginUser) {
return registryClient.getServerList(RegistryNodeType.WORKER)
.stream()
.map((Server server) -> {
WorkerServerModel model = new WorkerServerModel();
model.setId(server.getId());
model.setHost(server.getHost());
model.setPort(server.getPort());
model.setZkDirectories(Sets.newHashSet(server.getZkDirectory()));
model.setResInfo(server.getResInfo());
model.setCreateTime(server.getCreateTime());
model.setLastHeartbeatTime(server.getLastHeartbeatTime());
return model;
})
.collect(Collectors.toList());
}
@Override
public List<Server> getServerListFromRegistry(boolean isMaster) {
return isMaster
? registryClient.getServerList(RegistryNodeType.MASTER)
: registryClient.getServerList(RegistryNodeType.WORKER);
}
}

25
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/MonitorControllerTest.java

@ -41,8 +41,7 @@ public class MonitorControllerTest extends AbstractControllerTest {
@Test
public void testListMaster() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/masters")
MvcResult mvcResult = mockMvc.perform(get("/monitor/MASTER")
.header(SESSION_ID, sessionId)
/* .param("type", ResourceType.FILE.name()) */)
.andExpect(status().isOk())
@ -59,7 +58,7 @@ public class MonitorControllerTest extends AbstractControllerTest {
@Test
public void testListWorker() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/workers")
MvcResult mvcResult = mockMvc.perform(get("/monitor/WORKER")
.header(SESSION_ID, sessionId)
/* .param("type", ResourceType.FILE.name()) */)
.andExpect(status().isOk())
@ -74,8 +73,9 @@ public class MonitorControllerTest extends AbstractControllerTest {
}
@Test
public void testQueryDatabaseState() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/databases")
public void testListAlert() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/ALERT_SERVER")
.header(SESSION_ID, sessionId)
/* .param("type", ResourceType.FILE.name()) */)
.andExpect(status().isOk())
@ -89,4 +89,19 @@ public class MonitorControllerTest extends AbstractControllerTest {
logger.info(mvcResult.getResponse().getContentAsString());
}
@Test
public void testQueryDatabaseState() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/databases")
.header(SESSION_ID, sessionId))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
result.getCode().equals(Status.SUCCESS.getCode());
Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
logger.info(mvcResult.getResponse().getContentAsString());
}
}

5
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ExecuteFunctionServiceTest.java

@ -67,6 +67,7 @@ import org.apache.dolphinscheduler.dao.mapper.TaskDefinitionMapper;
import org.apache.dolphinscheduler.dao.mapper.TaskGroupQueueMapper;
import org.apache.dolphinscheduler.dao.mapper.TenantMapper;
import org.apache.dolphinscheduler.dao.repository.ProcessInstanceDao;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import org.apache.dolphinscheduler.service.command.CommandService;
import org.apache.dolphinscheduler.service.process.ProcessService;
import org.apache.dolphinscheduler.service.process.TriggerRelationService;
@ -242,7 +243,7 @@ public class ExecuteFunctionServiceTest {
Mockito.when(processService.getTenantForProcess(tenantCode, userId)).thenReturn(tenantCode);
doReturn(1).when(commandService).createCommand(argThat(c -> c.getId() == null));
doReturn(0).when(commandService).createCommand(argThat(c -> c.getId() != null));
Mockito.when(monitorService.getServerListFromRegistry(true)).thenReturn(getMasterServersList());
Mockito.when(monitorService.listServer(RegistryNodeType.MASTER)).thenReturn(getMasterServersList());
Mockito.when(processService.findProcessInstanceDetailById(processInstanceId))
.thenReturn(Optional.ofNullable(processInstance));
Mockito.when(processService.findProcessDefinition(1L, 1)).thenReturn(this.processDefinition);
@ -498,7 +499,7 @@ public class ExecuteFunctionServiceTest {
@Test
public void testNoMasterServers() {
Mockito.when(monitorService.getServerListFromRegistry(true)).thenReturn(new ArrayList<>());
Mockito.when(monitorService.listServer(RegistryNodeType.MASTER)).thenReturn(new ArrayList<>());
Assertions.assertThrows(ServiceException.class, () -> executorService.execProcessInstance(
loginUser,

4
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/MonitorServiceTest.java

@ -98,13 +98,13 @@ public class MonitorServiceTest {
public void testQueryMaster() {
mockPermissionCheck(ApiFuncIdentificationConstant.MONITOR_MASTER_VIEW, true);
Mockito.when(registryClient.getServerList(RegistryNodeType.MASTER)).thenReturn(getServerList());
assertDoesNotThrow(() -> monitorService.queryMaster(user));
assertDoesNotThrow(() -> monitorService.listServer(RegistryNodeType.MASTER));
}
@Test
public void testQueryWorker() {
Mockito.when(registryClient.getServerList(RegistryNodeType.WORKER)).thenReturn(getServerList());
AssertionsHelper.assertDoesNotThrow(() -> monitorService.queryWorker(user));
AssertionsHelper.assertDoesNotThrow(() -> monitorService.listServer(RegistryNodeType.WORKER));
}
@Test

7
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/CommandMapper.java

@ -26,6 +26,8 @@ import java.util.Date;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* command mapper interface
@ -50,7 +52,7 @@ public interface CommandMapper extends BaseMapper<Command> {
*
* @return
*/
List<Command> queryCommandPage(@Param("limit") int limit, @Param("offset") int offset);
IPage<Command> queryCommandPage(Page<Command> page);
List<Command> queryCommandByIdSlot(@Param("currentSlotIndex") int currentSlotIndex,
@Param("totalSlot") int totalSlot,
@ -58,4 +60,7 @@ public interface CommandMapper extends BaseMapper<Command> {
@Param("fetchNumber") int fetchNum);
void deleteByWorkflowInstanceIds(@Param("workflowInstanceIds") List<Integer> workflowInstanceIds);
IPage<Command> queryCommandPageByIds(Page<Command> page,
@Param("workflowDefinitionCodes") List<Long> workflowDefinitionCodes);
}

7
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.java

@ -26,6 +26,8 @@ import java.util.Date;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* error command mapper interface
@ -43,4 +45,9 @@ public interface ErrorCommandMapper extends BaseMapper<ErrorCommand> {
@Param("startTime") Date startTime,
@Param("endTime") Date endTime,
@Param("projectCodes") List<Long> projectCodes);
IPage<ErrorCommand> queryErrorCommandPage(Page<ErrorCommand> page);
IPage<ErrorCommand> queryErrorCommandPageByIds(Page<ErrorCommand> page,
@Param("workflowDefinitionCodes") List<Long> workflowDefinitionCodes);
}

1
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.java

@ -188,4 +188,5 @@ public interface ProcessDefinitionMapper extends BaseMapper<ProcessDefinition> {
* @return project ids list
*/
List<Integer> listProjectIds();
List<Long> queryDefinitionCodeListByProjectCodes(@Param("projectCodes") List<Long> projectCodes);
}

16
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/CommandMapper.xml

@ -34,10 +34,22 @@
group by cmd.command_type
</select>
<select id="queryCommandPage" resultType="org.apache.dolphinscheduler.dao.entity.Command">
select *
select
*
from t_ds_command
where 1 = 1
order by process_instance_priority, id asc
</select>
<select id="queryCommandPageByIds" resultType="org.apache.dolphinscheduler.dao.entity.Command">
select
*
from t_ds_command
where process_definition_code in
<foreach item="id" index="index" collection="workflowDefinitionCodes" open="(" separator="," close=")">
#{id}
</foreach>
order by process_instance_priority, id asc
limit #{limit} offset #{offset}
</select>
<select id="queryCommandByIdSlot" resultType="org.apache.dolphinscheduler.dao.entity.Command">

19
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml

@ -33,4 +33,23 @@
</if>
group by cmd.command_type
</select>
<select id="queryErrorCommandPage" resultType="org.apache.dolphinscheduler.dao.entity.ErrorCommand">
select
*
from t_ds_error_command
order by process_instance_priority, id asc
</select>
<select id="queryErrorCommandPageByIds" resultType="org.apache.dolphinscheduler.dao.entity.ErrorCommand">
select
*
from t_ds_error_command
where process_definition_code in
<foreach item="id" index="index" collection="workflowDefinitionCodes" open="(" separator="," close=")">
#{id}
</foreach>
order by process_instance_priority, id asc
</select>
</mapper>

10
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.xml

@ -208,4 +208,14 @@
SELECT DISTINCT(id) as project_id
FROM t_ds_project
</select>
<select id="queryDefinitionCodeListByProjectCodes" resultType="java.lang.Long">
select
code
from t_ds_process_definition
where project_code in
<foreach collection="projectCodes" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</select>
</mapper>

3
dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/CommandMapperTest.java

@ -42,6 +42,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
/**
@ -135,7 +136,7 @@ public class CommandMapperTest extends BaseDaoTest {
createCommand(CommandType.START_PROCESS, processDefinition.getCode());
List<Command> actualCommand = commandMapper.queryCommandPage(1, 0);
List<Command> actualCommand = commandMapper.selectList(new QueryWrapper<>());
Assertions.assertNotNull(actualCommand);
}

1
dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/enums/RegistryNodeType.java

@ -37,5 +37,4 @@ public enum RegistryNodeType {
private final String name;
private final String registryPath;
}

4
dolphinscheduler-ui/src/layouts/content/use-dataList.ts

@ -255,6 +255,10 @@ export function useDataList() {
label: t('menu.worker'),
key: '/monitor/worker'
},
{
label: t('menu.alert_server'),
key: '/monitor/alert_server'
},
{
label: t('menu.db'),
key: '/monitor/db'

1
dolphinscheduler-ui/src/locales/en_US/menu.ts

@ -40,6 +40,7 @@ export default {
service_manage: 'Service Manage',
master: 'Master',
worker: 'Worker',
alert_server: 'Alert Server',
db: 'DB',
statistical_manage: 'Statistical Manage',
statistics: 'Statistics',

6
dolphinscheduler-ui/src/locales/en_US/monitor.ts

@ -35,6 +35,7 @@ export default {
memory_usage: 'Memory Usage',
disk_available: 'Disk Available',
load_average: 'Load Average',
thread_pool_usage: 'Thread Pool Usage',
create_time: 'Create Time',
last_heartbeat_time: 'Last Heartbeat Time',
directory_detail: 'Directory Detail',
@ -44,6 +45,11 @@ export default {
worker_no_data_result_desc:
'Currently, there are no worker nodes exist, please create a worker node and refresh this page'
},
alert_server: {
alert_server_no_data_result_title: 'No Alert Server Nodes Exist',
alert_server_no_data_result_desc:
'Currently, there are no alert server nodes exist, please create a alert server node and refresh this page'
},
db: {
health_state: 'Health State',
max_connections: 'Max Connections',

1
dolphinscheduler-ui/src/locales/zh_CN/menu.ts

@ -41,6 +41,7 @@ export default {
service_manage: '服务管理',
master: 'Master',
worker: 'Worker',
alert_server: 'Alert Server',
db: 'DB',
statistical_manage: '统计管理',
statistics: 'Statistics',

6
dolphinscheduler-ui/src/locales/zh_CN/monitor.ts

@ -35,6 +35,7 @@ export default {
memory_usage: '内存使用量',
disk_available: '磁盘可用容量',
load_average: '平均负载量',
thread_pool_usage: '线程池使用量',
create_time: '创建时间',
last_heartbeat_time: '最后心跳时间',
directory_detail: '目录详情',
@ -44,6 +45,11 @@ export default {
worker_no_data_result_desc:
'目前没有任何Worker节点,请先创建Worker节点,再访问该页面'
},
alert_server: {
alert_server_no_data_result_title: 'Alert Server节点不存在',
alert_server_no_data_result_desc:
'目前没有任何Alert Server节点,请先创建Alert Server节点,再访问该页面'
},
db: {
health_state: '健康状态',
max_connections: '最大连接数',

11
dolphinscheduler-ui/src/router/modules/monitor.ts

@ -51,6 +51,17 @@ export default {
auth: []
}
},
{
path: '/monitor/alert_server',
name: 'servers-alert-server',
component: components['monitor-servers-alert_server'],
meta: {
title: '服务管理-Alert Server',
activeMenu: 'monitor',
showSide: true,
auth: []
}
},
{
path: '/monitor/db',
name: 'servers-db',

8
dolphinscheduler-ui/src/service/modules/monitor/index.ts

@ -16,6 +16,7 @@
*/
import { axios } from '@/service/service'
import type { ServerNodeType } from './types'
export function queryDatabaseState(): any {
return axios({
@ -37,3 +38,10 @@ export function listWorker(): any {
method: 'get'
})
}
export function listMonitorServerNode(nodeType: ServerNodeType): any {
return axios({
url: `/monitor/${nodeType}`,
method: 'get'
})
}

31
dolphinscheduler-ui/src/service/modules/monitor/types.ts

@ -25,7 +25,9 @@ interface DatabaseRes {
date: string
}
interface MasterNode {
type ServerNodeType = 'MASTER' | 'WORKER' | 'ALERT_SERVER'
interface ServerNode {
id: number
host: string
port: number
@ -35,14 +37,23 @@ interface MasterNode {
lastHeartbeatTime: string
}
interface WorkerNode {
id: number
host: string
port: number
zkDirectories: Array<string>
resInfo: string
createTime: string
lastHeartbeatTime: string
interface MasterNode extends ServerNode {
serverStatus?: 'NORMAL' | 'BUZY'
}
interface WorkerNode extends ServerNode {
serverStatus?: 'NORMAL' | 'BUZY'
workerHostWeight?: number
threadPoolUsage?: number
}
export { DatabaseRes, MasterNode, WorkerNode }
interface AlertNode extends MasterNode {}
export {
DatabaseRes,
MasterNode,
WorkerNode,
ServerNodeType,
ServerNode,
AlertNode
}

18
dolphinscheduler-ui/src/service/modules/projects-analysis/index.ts

@ -16,7 +16,7 @@
*/
import { axios } from '@/service/service'
import { CodeReq, StateReq } from './types'
import { ListReq, CodeReq, StateReq } from './types'
export function countCommandState(): any {
return axios({
@ -55,3 +55,19 @@ export function countTaskState(params: StateReq): any {
params
})
}
export function queryListCommandPaging(params: ListReq): any {
return axios({
url: '/projects/analysis/listCommand',
method: 'get',
params
})
}
export function queryListErrorCommandPaging(params: ListReq): any {
return axios({
url: '/projects/analysis/listErrorCommand',
method: 'get',
params
})
}

9
dolphinscheduler-ui/src/service/modules/projects-analysis/types.ts

@ -66,6 +66,12 @@ interface CommandStateRes {
commandState: string
}
interface ListReq {
pageNo: number
pageSize: number
searchVal?: string
}
export {
CodeReq,
StateReq,
@ -73,5 +79,6 @@ export {
WorkflowInstanceCountVo,
TaskInstanceCountVo,
TaskQueueRes,
CommandStateRes
CommandStateRes,
ListReq
}

43
dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.module.scss

@ -0,0 +1,43 @@
/*
* 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.
*/
@mixin base {
font-size: 5vw;
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
}
.card {
@include base;
}
.load-average {
@include base;
color: var(--n-color-target);
}
.link-btn {
color: var(--n-color-target);
cursor: pointer;
&:hover {
color: var(--n-color-target);
opacity: 0.8;
}
}

189
dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.tsx

@ -0,0 +1,189 @@
/*
* 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, onMounted, ref, toRefs } from 'vue'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace, NTag } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useServerNode } from './use-server-node'
import styles from './index.module.scss'
import Card from '@/components/card'
import Result from '@/components/result'
import Gauge from '@/components/chart/modules/Gauge'
import NodeModal from './node-modal'
import type { Ref } from 'vue'
import type { RowData } from 'naive-ui/es/data-table/src/interface'
import type { AlertNode } from '@/service/modules/monitor/types'
import { capitalize } from 'lodash'
const alertServer = defineComponent({
name: 'alertServer',
setup() {
const showModalRef = ref(false)
const { t } = useI18n()
const { variables, getTableData } = useServerNode()
const zkDirectoryRef: Ref<Array<RowData>> = ref([])
const clickDetails = (zkDirectories: string) => {
zkDirectoryRef.value = [{ directory: zkDirectories, index: 1 }]
showModalRef.value = true
}
const onConfirmModal = () => {
showModalRef.value = false
}
onMounted(() => {
getTableData()
})
return {
t,
...toRefs(variables),
clickDetails,
onConfirmModal,
showModalRef,
zkDirectoryRef
}
},
render() {
const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } =
this
const renderNodeServerStatusTag = (item: AlertNode) => {
const serverStatus = JSON.parse(item.resInfo)?.serverStatus
if (!serverStatus) return ''
return (
<NTag type={serverStatus === 'NORMAL' ? 'info' : 'warning'}>
{capitalize(serverStatus)}
</NTag>
)
}
return this.data.length < 1 ? (
<Result
title={t('monitor.alert_server.alert_server_no_data_result_title')}
description={t('monitor.alert_server.alert_server_no_data_result_desc')}
status={'info'}
size={'medium'}
/>
) : (
<>
<NSpace vertical size={25}>
{this.data.map((item: AlertNode) => {
return (
<NSpace vertical>
<NCard>
<NSpace
justify='space-between'
style={{
'line-height': '28px'
}}
>
<NSpace>
{renderNodeServerStatusTag(item)}
<span>{`${t('monitor.master.host')}: ${
item ? item.host : ' - '
}`}</span>
<span
class={styles['link-btn']}
onClick={() => clickDetails(item.zkDirectory)}
>
{t('monitor.master.directory_detail')}
</span>
</NSpace>
<NSpace>
<span>{`${t('monitor.master.create_time')}: ${
item ? item.createTime : ' - '
}`}</span>
<span>{`${t('monitor.master.last_heartbeat_time')}: ${
item ? item.lastHeartbeatTime : ' - '
}`}</span>
</NSpace>
</NSpace>
</NCard>
<NGrid x-gap='12' cols='4'>
<NGi>
<Card title={t('monitor.master.cpu_usage')}>
<div class={styles.card}>
{item && (
<Gauge
data={(
JSON.parse(item.resInfo).cpuUsage * 100
).toFixed(2)}
/>
)}
</div>
</Card>
</NGi>
<NGi>
<Card title={t('monitor.master.memory_usage')}>
<div class={styles.card}>
{item && (
<Gauge
data={(
JSON.parse(item.resInfo).memoryUsage * 100
).toFixed(2)}
/>
)}
</div>
</Card>
</NGi>
<NGi>
<Card title={t('monitor.master.disk_available')}>
<div class={[styles.card, styles['load-average']]}>
{item && (
<NNumberAnimation
precision={2}
from={0}
to={JSON.parse(item.resInfo).diskAvailable}
/>
)}
</div>
</Card>
</NGi>
<NGi>
<Card title={t('monitor.master.load_average')}>
<div class={[styles.card, styles['load-average']]}>
{item && (
<NNumberAnimation
precision={2}
from={0}
to={JSON.parse(item.resInfo).loadAverage}
/>
)}
</div>
</Card>
</NGi>
</NGrid>
</NSpace>
)
})}
</NSpace>
<NodeModal
showModal={showModalRef}
data={zkDirectoryRef}
onConfirmModal={onConfirmModal}
></NodeModal>
</>
)
}
})
export default alertServer

80
dolphinscheduler-ui/src/views/monitor/servers/alert_server/node-modal.tsx

@ -0,0 +1,80 @@
/*
* 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 } from 'vue'
import { useI18n } from 'vue-i18n'
import { NDataTable } from 'naive-ui'
import Modal from '@/components/modal'
import type { PropType } from 'vue'
import type {
RowData,
TableColumns
} from 'naive-ui/es/data-table/src/interface'
const props = {
showModal: {
type: Boolean as PropType<boolean>,
default: false
},
data: {
type: Array as PropType<Array<RowData>>,
default: () => []
}
}
const NodeModal = defineComponent({
props,
emits: ['confirmModal'],
setup(props, ctx) {
const { t } = useI18n()
const columnsRef: TableColumns<any> = [
{ title: '#', key: 'index', render: (row, index) => index + 1 },
{ title: t('monitor.master.directory'), key: 'directory' }
]
const onConfirm = () => {
ctx.emit('confirmModal')
}
return { t, columnsRef, onConfirm }
},
render() {
const { t, columnsRef, onConfirm } = this
return (
<Modal
title={t('monitor.master.directory_detail')}
show={this.showModal}
cancelShow={false}
onConfirm={onConfirm}
>
{{
default: () => (
<NDataTable
columns={columnsRef}
data={this.data}
striped
size={'small'}
/>
)
}}
</Modal>
)
}
})
export default NodeModal

38
dolphinscheduler-ui/src/views/monitor/servers/alert_server/use-server-node.ts

@ -0,0 +1,38 @@
/*
* 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 } from 'vue'
import { useAsyncState } from '@vueuse/core'
import { listMonitorServerNode } from '@/service/modules/monitor'
import type { AlertNode } from '@/service/modules/monitor/types'
export function useServerNode() {
const variables = reactive({
data: []
})
const getTableData = () => {
const { state } = useAsyncState(
listMonitorServerNode('ALERT_SERVER').then((res: Array<AlertNode>) => {
variables.data = res as any
}),
[]
)
return state
}
return { variables, getTableData }
}

24
dolphinscheduler-ui/src/views/monitor/servers/master/index.tsx

@ -16,7 +16,7 @@
*/
import { defineComponent, onMounted, ref, toRefs } from 'vue'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace } from 'naive-ui'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace, NTag } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useMaster } from './use-master'
import styles from './index.module.scss'
@ -27,6 +27,7 @@ import MasterModal from './master-modal'
import type { Ref } from 'vue'
import type { RowData } from 'naive-ui/es/data-table/src/interface'
import type { MasterNode } from '@/service/modules/monitor/types'
import { capitalize } from 'lodash'
const master = defineComponent({
name: 'master',
@ -62,6 +63,18 @@ const master = defineComponent({
const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } =
this
const renderNodeServerStatusTag = (item: MasterNode) => {
const serverStatus = JSON.parse(item.resInfo)?.serverStatus
if (!serverStatus) return ''
return (
<NTag type={serverStatus === 'NORMAL' ? 'info' : 'warning'}>
{capitalize(serverStatus)}
</NTag>
)
}
return this.data.length < 1 ? (
<Result
title={t('monitor.master.master_no_data_result_title')}
@ -76,8 +89,15 @@ const master = defineComponent({
return (
<NSpace vertical>
<NCard>
<NSpace justify='space-between'>
<NSpace
justify='space-between'
style={{
'line-height': '28px'
}}
>
<NSpace>
{renderNodeServerStatusTag(item)}
<span>{`${t('monitor.master.host')}: ${
item ? item.host : ' - '
}`}</span>

4
dolphinscheduler-ui/src/views/monitor/servers/master/use-master.ts

@ -17,7 +17,7 @@
import { reactive } from 'vue'
import { useAsyncState } from '@vueuse/core'
import { listMaster } from '@/service/modules/monitor'
import { listMonitorServerNode } from '@/service/modules/monitor'
import type { MasterNode } from '@/service/modules/monitor/types'
export function useMaster() {
@ -26,7 +26,7 @@ export function useMaster() {
})
const getTableMaster = () => {
const { state } = useAsyncState(
listMaster().then((res: Array<MasterNode>) => {
listMonitorServerNode('MASTER').then((res: Array<MasterNode>) => {
variables.data = res as any
}),
[]

63
dolphinscheduler-ui/src/views/monitor/servers/worker/index.tsx

@ -16,7 +16,7 @@
*/
import { defineComponent, onMounted, ref, toRefs } from 'vue'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace } from 'naive-ui'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace, NTag } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useWorker } from './use-worker'
import styles from './index.module.scss'
@ -27,6 +27,7 @@ import WorkerModal from './worker-modal'
import type { Ref } from 'vue'
import type { RowData } from 'naive-ui/es/data-table/src/interface'
import type { WorkerNode } from '@/service/modules/monitor/types'
import { capitalize } from 'lodash'
const worker = defineComponent({
name: 'worker',
@ -36,12 +37,8 @@ const worker = defineComponent({
const { variables, getTableWorker } = useWorker()
const zkDirectoryRef: Ref<Array<RowData>> = ref([])
const clickDetails = (zkDirectories: Array<string>) => {
zkDirectoryRef.value = zkDirectories.map((zkItem) => {
return {
directory: zkItem
}
})
const clickDetails = (zkDirectories: string) => {
zkDirectoryRef.value = [{ directory: zkDirectories, index: 1 }]
showModalRef.value = true
}
@ -66,6 +63,18 @@ const worker = defineComponent({
const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } =
this
const renderNodeServerStatusTag = (item: WorkerNode) => {
const serverStatus = JSON.parse(item.resInfo)?.serverStatus
if (!serverStatus) return ''
return (
<NTag type={serverStatus === 'NORMAL' ? 'info' : 'warning'}>
{capitalize(serverStatus)}
</NTag>
)
}
return this.data.length < 1 ? (
<Result
title={t('monitor.worker.worker_no_data_result_title')}
@ -80,14 +89,21 @@ const worker = defineComponent({
return (
<NSpace vertical>
<NCard>
<NSpace justify='space-between'>
<NSpace
justify='space-between'
style={{
'line-height': '28px'
}}
>
<NSpace>
{renderNodeServerStatusTag(item)}
<span>{`${t('monitor.worker.host')}: ${
item ? item.host : ' - '
}`}</span>
<span
class={styles['link-btn']}
onClick={() => clickDetails(item.zkDirectories)}
onClick={() => clickDetails(item.zkDirectory)}
>
{t('monitor.worker.directory_detail')}
</span>
@ -102,7 +118,7 @@ const worker = defineComponent({
</NSpace>
</NSpace>
</NCard>
<NGrid x-gap='12' cols='4'>
<NGrid x-gap='12' cols='5'>
<NGi>
<Card title={t('monitor.worker.cpu_usage')}>
<div class={styles.card}>
@ -155,6 +171,33 @@ const worker = defineComponent({
</div>
</Card>
</NGi>
<NGi>
<Card title={t('monitor.worker.thread_pool_usage')}>
<div
class={[styles.card, styles['load-average']]}
style={{
'font-size': '90px'
}}
>
{item && (
<>
<NNumberAnimation
precision={0}
from={0}
to={JSON.parse(item.resInfo).threadPoolUsage}
/>
/
<NNumberAnimation
precision={0}
from={0}
to={JSON.parse(item.resInfo).workerHostWeight}
/>
</>
)}
</div>
</Card>
</NGi>
</NGrid>
</NSpace>
)

4
dolphinscheduler-ui/src/views/monitor/servers/worker/use-worker.ts

@ -17,7 +17,7 @@
import { reactive } from 'vue'
import { useAsyncState } from '@vueuse/core'
import { listWorker } from '@/service/modules/monitor'
import { listMonitorServerNode } from '@/service/modules/monitor'
import type { WorkerNode } from '@/service/modules/monitor/types'
export function useWorker() {
@ -27,7 +27,7 @@ export function useWorker() {
const getTableWorker = () => {
const { state } = useAsyncState(
listWorker().then((res: Array<WorkerNode>) => {
listMonitorServerNode('WORKER').then((res: Array<WorkerNode>) => {
variables.data = res as any
}),
[]

76
dolphinscheduler-ui/src/views/monitor/statistics/statistics/index.tsx

@ -15,58 +15,44 @@
* limitations under the License.
*/
import { defineComponent, ref } from 'vue'
import { NGrid, NGi, NNumberAnimation } from 'naive-ui'
import { useStatistics } from './use-statistics'
import { useI18n } from 'vue-i18n'
import Card from '@/components/card'
import styles from './index.module.scss'
import { defineComponent } from 'vue'
import { NGrid, NGi, NTabs, NTabPane, NCard } from 'naive-ui'
import ListCommandTable from './list-command-table'
import ListErrorCommandTable from './list-error-command-table'
const statistics = defineComponent({
name: 'statistics',
setup() {
const { t } = useI18n()
const { getStatistics } = useStatistics()
const statisticsRef = ref(getStatistics())
setup() {},
return { t, statisticsRef }
},
render() {
const { t, statisticsRef } = this
return (
<NGrid x-gap='12' y-gap='8' cols='2' responsive='screen'>
<NGi>
<Card
title={t(
'monitor.statistics.command_number_of_waiting_for_running'
)}
>
<div class={styles.connections}>
{statisticsRef.command.length > 0 && (
<NNumberAnimation
from={0}
to={statisticsRef.command
.map((item) => item.normalCount)
.reduce((prev, next) => prev + next)}
/>
)}
</div>
</Card>
</NGi>
<NGrid x-gap='12' y-gap='8' cols='1' responsive='screen'>
<NGi>
<Card title={t('monitor.statistics.failure_command_number')}>
<div class={styles.connections}>
{statisticsRef.command.length > 0 && (
<NNumberAnimation
from={0}
to={statisticsRef.command
.map((item) => item.errorCount)
.reduce((prev, next) => prev + next)}
/>
)}
</div>
</Card>
<NCard>
<NTabs
type='card'
animated
pane-style={{
padding: '0px',
border: 'none'
}}
>
<NTabPane
name='command'
tab='Command Statistics List'
display-directiv='show'
>
<ListCommandTable></ListCommandTable>
</NTabPane>
<NTabPane
name='command-error'
tab='Failure Command Statistics List'
display-directiv='show'
>
<ListErrorCommandTable></ListErrorCommandTable>
</NTabPane>
</NTabs>
</NCard>
</NGi>
</NGrid>
)

233
dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-command-table.tsx

@ -0,0 +1,233 @@
/*
* 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,
onMounted,
toRefs,
watch,
reactive,
ref,
h
} from 'vue'
import { NSpace, NDataTable, NPagination } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import Card from '@/components/card'
import {
COLUMN_WIDTH_CONFIG,
calculateTableWidth,
DefaultTableWidth
} from '@/common/column-width-config'
import { useAsyncState } from '@vueuse/core'
import { queryListCommandPaging } from '@/service/modules/projects-analysis'
const ListCommandTable = defineComponent({
name: 'list-command-table',
setup() {
const { t } = useI18n()
const variables = reactive({
columns: [],
tableWidth: DefaultTableWidth,
tableData: [],
page: ref(1),
pageSize: ref(10),
userName: ref(null),
totalPage: ref(1),
loadingRef: ref(false)
})
const createColumns = (variables: any) => {
variables.columns = [
{
title: 'ID',
key: 'id',
...COLUMN_WIDTH_CONFIG['index']
},
{
title: 'Command Type',
key: 'commandType',
...COLUMN_WIDTH_CONFIG['userName']
},
{
title: 'Command Param',
key: 'commandParam',
...COLUMN_WIDTH_CONFIG['linkName']
},
{
title: 'Task Info',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`Definition Code:${row.processDefinitionCode} `,
h('br'),
`Definition Version:${row.processDefinitionVersion} `,
h('br'),
`Instance Id:${row.processInstanceId} `,
h('br'),
`Instance Priority:${row.processInstancePriority} `
])
}
},
{
title: 'Task Params',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`DryRun:${row.dryRun} `,
h('br'),
`Environment Code:${row.environmentCode} `,
h('br'),
`Failure Strategy:${row.failureStrategy} `,
h('br'),
`Task Depend Type:${row.taskDependType} `
])
}
},
{
title: 'Worker Info',
key: 'id',
width: 220,
render: (row: any) => {
return h('div', [
`Worker Group:${row.workerGroup} `,
h('br'),
`Tenant Code:${row.tenantCode} `,
h('br'),
`Test Flag:${row.testFlag} `
])
}
},
{
title: 'Warning Info',
key: 'id',
width: 200,
render: (row: any) => {
return h('div', [
`Warning Group Id:${row.warningGroupId} `,
h('br'),
`Warning Type:${row.warningType} `
])
}
},
{
title: 'Executor Id',
key: 'executorId',
...COLUMN_WIDTH_CONFIG['type']
},
{
title: 'Time',
key: 'startTime',
width: 280,
render: (row: any) => {
return h('div', [
`Start Time:${row.startTime} `,
h('br'),
`Update Time:${row.updateTime} `,
h('br'),
`Schedule Time:${row.scheduleTime} `
])
}
}
]
if (variables.tableWidth) {
variables.tableWidth = calculateTableWidth(variables.columns)
}
}
const getTableData = () => {
if (variables.loadingRef) return
variables.loadingRef = true
const data = {
pageSize: variables.pageSize,
pageNo: variables.page
}
const { state } = useAsyncState(
queryListCommandPaging(data).then((res: any) => {
variables.totalPage = res.totalPage
variables.tableData = res.totalList
variables.loadingRef = false
}),
{}
)
return state
}
const onUpdatePageSize = () => {
variables.page = 1
getTableData()
}
onMounted(() => {
createColumns(variables)
getTableData()
})
watch(useI18n().locale, () => {
createColumns(variables)
})
return {
t,
...toRefs(variables),
getTableData,
onUpdatePageSize
}
},
render() {
const { getTableData, onUpdatePageSize, loadingRef } = this
return (
<NSpace vertical>
<Card>
<NSpace vertical>
<NDataTable
size={'small'}
loading={loadingRef}
columns={this.columns}
scrollX={this.tableWidth}
data={this.tableData}
/>
<NSpace justify='center'>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={getTableData}
onUpdatePageSize={onUpdatePageSize}
/>
</NSpace>
</NSpace>
</Card>
</NSpace>
)
}
})
export default ListCommandTable

237
dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-error-command-table.tsx

@ -0,0 +1,237 @@
/*
* 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,
onMounted,
toRefs,
watch,
reactive,
ref,
h
} from 'vue'
import { NSpace, NDataTable, NPagination } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import Card from '@/components/card'
import {
COLUMN_WIDTH_CONFIG,
calculateTableWidth,
DefaultTableWidth
} from '@/common/column-width-config'
import { useAsyncState } from '@vueuse/core'
import { queryListErrorCommandPaging } from '@/service/modules/projects-analysis'
const ListErrorCommandTable = defineComponent({
name: 'list-error-command-table',
setup() {
const { t } = useI18n()
const variables = reactive({
columns: [],
tableWidth: DefaultTableWidth,
tableData: [],
page: ref(1),
pageSize: ref(10),
userName: ref(null),
totalPage: ref(1),
loadingRef: ref(false)
})
const createColumns = (variables: any) => {
variables.columns = [
{
title: 'ID',
key: 'id',
...COLUMN_WIDTH_CONFIG['index']
},
{
title: 'Command Type',
key: 'commandType',
...COLUMN_WIDTH_CONFIG['userName']
},
{
title: 'Command Param',
key: 'commandParam',
...COLUMN_WIDTH_CONFIG['linkName']
},
{
title: 'Task Info',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`Definition Code:${row.processDefinitionCode} `,
h('br'),
`Definition Version:${row.processDefinitionVersion} `,
h('br'),
`Instance Id:${row.processInstanceId} `,
h('br'),
`Instance Priority:${row.processInstancePriority} `
])
}
},
{
title: 'Task Params',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`DryRun:${row.dryRun} `,
h('br'),
`Environment Code:${row.environmentCode} `,
h('br'),
`Failure Strategy:${row.failureStrategy} `,
h('br'),
`Task Depend Type:${row.taskDependType} `
])
}
},
{
title: 'Worker Info',
key: 'id',
width: 220,
render: (row: any) => {
return h('div', [
`Worker Group:${row.workerGroup} `,
h('br'),
`Tenant Code:${row.tenantCode} `,
h('br'),
`Test Flag:${row.testFlag} `
])
}
},
{
title: 'Warning Info',
key: 'id',
width: 200,
render: (row: any) => {
return h('div', [
`Warning Group Id:${row.warningGroupId} `,
h('br'),
`Warning Type:${row.warningType} `
])
}
},
{
title: 'Message',
key: 'message',
...COLUMN_WIDTH_CONFIG['linkName']
},
{
title: 'Executor Id',
key: 'executorId',
...COLUMN_WIDTH_CONFIG['type']
},
{
title: 'Time',
key: 'startTime',
width: 280,
render: (row: any) => {
return h('div', [
`Start Time:${row.startTime || '-'} `,
h('br'),
`Update Time:${row.updateTime || '-'} `,
h('br'),
`Schedule Time:${row.scheduleTime || '-'} `
])
}
}
]
if (variables.tableWidth) {
variables.tableWidth = calculateTableWidth(variables.columns)
}
}
const getTableData = () => {
if (variables.loadingRef) return
variables.loadingRef = true
const data = {
pageSize: variables.pageSize,
pageNo: variables.page
}
const { state } = useAsyncState(
queryListErrorCommandPaging(data).then((res: any) => {
variables.totalPage = res.totalPage
variables.tableData = res.totalList
variables.loadingRef = false
}),
{}
)
return state
}
const onUpdatePageSize = () => {
variables.page = 1
getTableData()
}
onMounted(() => {
createColumns(variables)
getTableData()
})
watch(useI18n().locale, () => {
createColumns(variables)
})
return {
t,
...toRefs(variables),
getTableData,
onUpdatePageSize
}
},
render() {
const { getTableData, onUpdatePageSize, loadingRef } = this
return (
<NSpace vertical>
<Card>
<NSpace vertical>
<NDataTable
loading={loadingRef}
columns={this.columns}
scrollX={this.tableWidth}
data={this.tableData}
/>
<NSpace justify='center'>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={getTableData}
onUpdatePageSize={onUpdatePageSize}
/>
</NSpace>
</NSpace>
</Card>
</NSpace>
)
}
})
export default ListErrorCommandTable
Loading…
Cancel
Save