You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by zh...@apache.org on 2022/01/16 02:08:53 UTC

[dolphinscheduler] branch dev updated: [Feature-7785][UI Next] Add a new page for the module of next ui to manage the task group option. (#8060)

This is an automated email from the ASF dual-hosted git repository.

zhongjiajie pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new a5f4e3d  [Feature-7785][UI Next] Add a new page for the module of next ui to manage the task group option. (#8060)
a5f4e3d is described below

commit a5f4e3de46f7019357d8a20d9fc5b04929712a14
Author: calvin <ji...@163.com>
AuthorDate: Sun Jan 16 10:08:42 2022 +0800

    [Feature-7785][UI Next] Add a new page for the module of next ui to manage the task group option. (#8060)
    
    * add a few settings
    
    * add a few pages
    
    * modify locals
    
    * modify pages
    
    * add taskGroupOption
    
    * merge from dev
    
    * modify taskGroupOption
    
    * modify task group
    
    * request api
    
    * modify taskGroupOptions
    
    * modify taskGroupOption
    
    * modify task group option
    
    * merge from dev
    
    * prettier the codes
    
    * fix a little issue
    
    * merge from dev
---
 dolphinscheduler-ui-next/.prettierrc.js            |  24 +--
 .../src/assets/styles/default.scss                 |  10 +-
 .../content/components/locales/index.module.scss   |   2 +-
 .../content/components/user/index.module.scss      |   2 +-
 .../src/layouts/content/use-dataList.ts            |  14 +-
 .../src/locales/modules/en_US.ts                   |  47 +++++
 .../src/locales/modules/zh_CN.ts                   |  50 ++++-
 .../src/router/modules/resources.ts                |  17 ++
 .../src/service/modules/task-group/index.ts        |  96 +++++++++
 .../modules/task-group/types.ts}                   |  55 +++--
 .../src/views/monitor/servers/db/index.module.scss |   2 -
 .../statistics/statistics/index.module.scss        |   2 -
 .../src/views/resource/file/index.module.scss      |   7 +-
 .../src/views/resource/file/index.tsx              |   2 +-
 .../views/resource/file/table/index.module.scss    |   3 +-
 .../resource/{file/table => }/index.module.scss    |  16 +-
 .../{file/table/index.module.scss => index.tsx}    |  15 +-
 .../taskGroupOption/components/form-modal.tsx      | 146 ++++++++++++++
 .../taskGroupOption/components/table-action.tsx    | 145 ++++++++++++++
 .../taskGroupOption}/index.module.scss             |  52 +++--
 .../src/views/resource/taskGroupOption/index.tsx   | 222 +++++++++++++++++++++
 .../src/views/resource/taskGroupOption/use-form.ts |  58 ++++++
 .../views/resource/taskGroupOption/use-table.ts    | 123 ++++++++++++
 23 files changed, 1034 insertions(+), 76 deletions(-)

diff --git a/dolphinscheduler-ui-next/.prettierrc.js b/dolphinscheduler-ui-next/.prettierrc.js
index 7bcb29e..59732ff 100644
--- a/dolphinscheduler-ui-next/.prettierrc.js
+++ b/dolphinscheduler-ui-next/.prettierrc.js
@@ -16,15 +16,15 @@
  */
 
 module.exports = {
-  "useTabs": false,
-  "semi": false,
-  "vueIndentScriptAndStyle": true,
-  "singleQuote": true,
-  "quoteProps": "as-needed",
-  "jsxBracketSameLine": false,
-  "jsxSingleQuote": true,
-  "arrowParens": "always",
-  "htmlWhitespaceSensitivity": "strict",
-  "endOfLine": "lf",
-  "trailingComma": "none"
-};
+  useTabs: false,
+  semi: false,
+  vueIndentScriptAndStyle: true,
+  singleQuote: true,
+  quoteProps: 'as-needed',
+  jsxBracketSameLine: false,
+  jsxSingleQuote: true,
+  arrowParens: 'always',
+  htmlWhitespaceSensitivity: 'strict',
+  endOfLine: 'lf',
+  trailingComma: 'none'
+}
diff --git a/dolphinscheduler-ui-next/src/assets/styles/default.scss b/dolphinscheduler-ui-next/src/assets/styles/default.scss
index fac4291..46f43f1 100644
--- a/dolphinscheduler-ui-next/src/assets/styles/default.scss
+++ b/dolphinscheduler-ui-next/src/assets/styles/default.scss
@@ -19,7 +19,8 @@
   outline: 0;
 }
 
-html, body {
+html,
+body {
   width: 100%;
   height: 100%;
   //scrollbar-width: none;
@@ -29,7 +30,12 @@ html, body {
   //}
 }
 
-html, body, p, dl, dd, dt {
+html,
+body,
+p,
+dl,
+dd,
+dt {
   margin: 0;
   padding: 0;
 }
diff --git a/dolphinscheduler-ui-next/src/layouts/content/components/locales/index.module.scss b/dolphinscheduler-ui-next/src/layouts/content/components/locales/index.module.scss
index 41b284a..2cf83fa 100644
--- a/dolphinscheduler-ui-next/src/layouts/content/components/locales/index.module.scss
+++ b/dolphinscheduler-ui-next/src/layouts/content/components/locales/index.module.scss
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- 
+
 .icon {
   margin: 0 12px;
 }
diff --git a/dolphinscheduler-ui-next/src/layouts/content/components/user/index.module.scss b/dolphinscheduler-ui-next/src/layouts/content/components/user/index.module.scss
index 41b284a..2cf83fa 100644
--- a/dolphinscheduler-ui-next/src/layouts/content/components/user/index.module.scss
+++ b/dolphinscheduler-ui-next/src/layouts/content/components/user/index.module.scss
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- 
+
 .icon {
   margin: 0 12px;
 }
diff --git a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
index 43b893c..2d23ae8 100644
--- a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
+++ b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
@@ -41,7 +41,8 @@ import {
   SlackOutlined,
   EnvironmentOutlined,
   KeyOutlined,
-  SafetyOutlined
+  SafetyOutlined,
+  GroupOutlined
 } from '@vicons/antd'
 
 export function useDataList() {
@@ -145,6 +146,17 @@ export function useDataList() {
                 key: 'function-manage'
               }
             ]
+          },
+          {
+            label: t('menu.task_group_manage'),
+            key: 'task-group-manage',
+            icon: renderIcon(GroupOutlined),
+            children: [
+              {
+                label: t('menu.task_group_option'),
+                key: 'task-group-option'
+              }
+            ]
           }
         ]
       },
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index 7a4286e..92d74e2 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -186,6 +186,53 @@ const resource = {
     file_details: 'File Details',
     return: 'Return',
     save: 'Save'
+  },
+  task_group_option: {
+    id: 'No.',
+    manage: 'Task group manage',
+    option: 'Task group option',
+    create: 'Create task group',
+    edit: 'Edit task group',
+    delete: 'Delete task group',
+    view_queue: 'View the queue of the task group',
+    switch_status: 'Switch status',
+    code: 'Task group code',
+    name: 'Task group name',
+    project_name: 'Project name',
+    resource_pool_size: 'Resource pool size',
+    resource_pool_size_be_a_number:
+      'The size of the task group resource pool should be more than 1',
+    resource_used_pool_size: 'Used resource',
+    desc: 'Task group desc',
+    status: 'Task group status',
+    enable_status: 'Enable',
+    disable_status: 'Disable',
+    please_enter_name: 'Please enter task group name',
+    please_enter_desc: 'Please enter task group description',
+    please_enter_resource_pool_size:
+      'Please enter task group resource pool size',
+    please_select_project: 'Please select a project',
+    create_time: 'Create time',
+    update_time: 'Update time',
+    actions: 'Actions',
+    please_enter_keywords: 'Please enter keywords'
+  },
+  task_group_queue: {
+    queue: 'Task group queue',
+    priority: 'Priority',
+    priority_be_a_number:
+      'The priority of the task group queue should be a positive number',
+    force_starting_status: 'Starting status',
+    in_queue: 'In queue',
+    task_status: 'Task status',
+    view: 'View task group queue',
+    the_status_of_waiting: 'Waiting into the queue',
+    the_status_of_queuing: 'Queuing',
+    the_status_of_releasing: 'Released',
+    modify_priority: 'Edit the priority of the task group queue',
+    priority_not_empty: 'The value of priority can not be empty',
+    priority_must_be_number: 'The value of priority should be number',
+    please_select_task_name: 'Please select a task name'
   }
 }
 
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index 21a6911..f15d13d 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -71,7 +71,10 @@ const menu = {
   worker_group_manage: 'Worker分组管理',
   yarn_queue_manage: 'Yarn队列管理',
   environment_manage: '环境管理',
-  token_manage: '令牌管理'
+  token_manage: '令牌管理',
+  task_group_manage: '任务组管理',
+  task_group_option: '任务组配置',
+  task_group_queue: '任务组队列'
 }
 
 const home = {
@@ -185,6 +188,51 @@ const resource = {
     file_details: '文件详情',
     return: '返回',
     save: '保存'
+  },
+  task_group_option: {
+    id: '编号',
+    manage: '任务组管理',
+    option: '任务组配置',
+    create: '创建任务组',
+    edit: '编辑任务组',
+    delete: '删除任务组',
+    view_queue: '查看任务组队列',
+    switch_status: '切换任务组状态',
+    code: '任务组编号',
+    name: '任务组名称',
+    project_name: '项目名称',
+    resource_pool_size: '资源容量',
+    resource_used_pool_size: '已用资源',
+    desc: '描述信息',
+    status: '任务组状态',
+    enable_status: '启用',
+    disable_status: '不可用',
+    please_enter_name: '请输入任务组名称',
+    please_enter_desc: '请输入任务组描述',
+    please_enter_resource_pool_size: '请输入资源容量大小',
+    resource_pool_size_be_a_number: '资源容量大小必须大于等于1的数值',
+    please_select_project: '请选择项目',
+    create_time: '创建时间',
+    update_time: '更新时间',
+    actions: '操作',
+    please_enter_keywords: '请输入搜索关键词'
+  },
+  task_group_queue: {
+    queue: '任务组队列',
+    priority: '组内优先级',
+    priority_be_a_number: '优先级必须是大于等于0的数值',
+    force_starting_status: '是否强制启动',
+    in_queue: '是否排队中',
+    task_status: '任务状态',
+    view_task_group_queue: '查看任务组队列',
+    the_status_of_waiting: '等待入队',
+    the_status_of_queuing: '排队中',
+    the_status_of_releasing: '已释放',
+    modify_priority: '修改优先级',
+    force_to_start_task: '强制启动',
+    priority_not_empty: '优先级不能为空',
+    priority_must_be_number: '优先级必须是数值',
+    please_select_task_name: '请选择节点名称'
   }
 }
 
diff --git a/dolphinscheduler-ui-next/src/router/modules/resources.ts b/dolphinscheduler-ui-next/src/router/modules/resources.ts
index 53769a2..d6e0f4b 100644
--- a/dolphinscheduler-ui-next/src/router/modules/resources.ts
+++ b/dolphinscheduler-ui-next/src/router/modules/resources.ts
@@ -76,6 +76,23 @@ export default {
       meta: {
         title: '文件创建'
       }
+    },
+    {
+      path: '/resource/task-group',
+      name: 'task-group-manage',
+      component: components['taskGroupOption'],
+      children: [
+        {
+          path: '/resource/task-group-option',
+          name: 'task-group-option',
+          component: components['taskGroupOption']
+        },
+        {
+          path: '/resource/task-group-queue',
+          name: 'task-group-queue',
+          component: components['taskGroupQueue']
+        }
+      ]
     }
   ]
 }
diff --git a/dolphinscheduler-ui-next/src/service/modules/task-group/index.ts b/dolphinscheduler-ui-next/src/service/modules/task-group/index.ts
new file mode 100644
index 0000000..08a4416
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/service/modules/task-group/index.ts
@@ -0,0 +1,96 @@
+/*
+ * 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 { axios } from '@/service/service'
+import {
+  ListReq,
+  TaskGroupIdReq,
+  TaskGroupReq,
+  TaskGroupUpdateReq
+} from './types'
+
+export function queryTaskGroupListPaging(params: ListReq): any {
+  return axios({
+    url: '/task-group/list-paging',
+    method: 'get',
+    params
+  })
+}
+
+export function queryTaskGroupListPagingByProjectCode(params: ListReq): any {
+  return axios({
+    url: '/task-group/query-list-by-projectCode',
+    method: 'get',
+    params
+  })
+}
+
+export function createTaskGroup(data: TaskGroupReq): any {
+  return axios({
+    url: '/task-group/create',
+    method: 'post',
+    data
+  })
+}
+
+export function updateTaskGroup(data: TaskGroupUpdateReq): any {
+  return axios({
+    url: '/task-group/update',
+    method: 'post',
+    data
+  })
+}
+
+export function closeTaskGroup(data: TaskGroupIdReq): any {
+  return axios({
+    url: '/task-group/close-task-group',
+    method: 'post',
+    data
+  })
+}
+
+export function startTaskGroup(data: TaskGroupIdReq): any {
+  return axios({
+    url: '/task-group/start-task-group',
+    method: 'post',
+    data
+  })
+}
+
+export function queryTaskListInTaskGroupQueueById(params: ListReq): any {
+  return axios({
+    url: '/task-group/query-list-by-group-id',
+    method: 'get',
+    params
+  })
+}
+
+export function modifyTaskGroupQueuePriority(data: TaskGroupIdReq): any {
+  return axios({
+    url: '/task-group/modifyPriority',
+    method: 'post',
+    data
+  })
+}
+
+export function forceStartTaskInQueue(data: TaskGroupIdReq): any {
+  return axios({
+    url: '/task-group/forceStart',
+    method: 'post',
+    data
+  })
+}
diff --git a/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss b/dolphinscheduler-ui-next/src/service/modules/task-group/types.ts
similarity index 52%
copy from dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss
copy to dolphinscheduler-ui-next/src/service/modules/task-group/types.ts
index f6ce120..ad3eabf 100644
--- a/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss
+++ b/dolphinscheduler-ui-next/src/service/modules/task-group/types.ts
@@ -15,29 +15,52 @@
  * limitations under the License.
  */
 
-@mixin base {
-  font-size: 100px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  min-height: 240px;
+interface ListReq {
+  pageNo: number
+  pageSize: number
+  searchVal?: string
 }
 
-.health {
-  @include base;
+interface TaskGroupIdReq {
+  id: number
 }
 
-.health-success {
-  color: limegreen;
+interface TaskGroupReq {
+  name: string
+  projectCode: string
+  groupSize: number
+  description: string
 }
 
-.health-error {
-  color: indianred;
-}
+interface TaskGroupUpdateReq extends TaskGroupReq, TaskGroupIdReq {}
 
-.connections {
-  @include base;
-  color: dodgerblue;
+interface TaskGroup {
+  id: number
+  name: string
+  projectCode: number
+  projectName: string
+  groupSize: number
+  useSize: number
+  status: number
+  description: string
+  createTime: string
+  updateTime: string
 }
 
+interface TaskGroupRes {
+  totalList: TaskGroup[]
+  total: number
+  totalPage: number
+  pageSize: number
+  currentPage: number
+  start: number
+}
 
+export {
+  ListReq,
+  TaskGroupIdReq,
+  TaskGroupReq,
+  TaskGroupUpdateReq,
+  TaskGroup,
+  TaskGroupRes
+}
diff --git a/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss b/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss
index f6ce120..7a70954 100644
--- a/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss
+++ b/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss
@@ -39,5 +39,3 @@
   @include base;
   color: dodgerblue;
 }
-
-
diff --git a/dolphinscheduler-ui-next/src/views/monitor/statistics/statistics/index.module.scss b/dolphinscheduler-ui-next/src/views/monitor/statistics/statistics/index.module.scss
index 3e1f059..23230df 100644
--- a/dolphinscheduler-ui-next/src/views/monitor/statistics/statistics/index.module.scss
+++ b/dolphinscheduler-ui-next/src/views/monitor/statistics/statistics/index.module.scss
@@ -23,5 +23,3 @@
   min-height: 160px;
   color: dodgerblue;
 }
-
-
diff --git a/dolphinscheduler-ui-next/src/views/resource/file/index.module.scss b/dolphinscheduler-ui-next/src/views/resource/file/index.module.scss
index d990390..2f0d90e 100644
--- a/dolphinscheduler-ui-next/src/views/resource/file/index.module.scss
+++ b/dolphinscheduler-ui-next/src/views/resource/file/index.module.scss
@@ -19,7 +19,7 @@
   width: 100%;
   background: #fff;
   padding-bottom: 20px;
-  >h2 {
+  > h2 {
     line-height: 60px;
     text-align: center;
     padding-right: 170px;
@@ -50,7 +50,8 @@
     tr {
       height: 40px;
       font-size: 12px;
-      th,td{
+      th,
+      td {
         &:nth-child(1) {
           width: 50px;
           text-align: center;
@@ -61,7 +62,7 @@
           width: 60px;
           text-align: center;
         }
-        >span {
+        > span {
           font-size: 12px;
           color: #555;
         }
diff --git a/dolphinscheduler-ui-next/src/views/resource/file/index.tsx b/dolphinscheduler-ui-next/src/views/resource/file/index.tsx
index 141c3dc..62fc894 100644
--- a/dolphinscheduler-ui-next/src/views/resource/file/index.tsx
+++ b/dolphinscheduler-ui-next/src/views/resource/file/index.tsx
@@ -53,7 +53,7 @@ export default defineComponent({
     const router: Router = useRouter()
     const fileId = ref(Number(router.currentRoute.value.params.id) || -1)
 
-    const reload:any = inject('reload')
+    const reload: any = inject('reload')
     const resourceListRef = ref()
     const folderShowRef = ref(false)
     const uploadShowRef = ref(false)
diff --git a/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss b/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss
index 4ec0732..488e8c0 100644
--- a/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss
+++ b/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss
@@ -15,11 +15,10 @@
  * limitations under the License.
  */
 
-
 .links {
   color: #2080f0;
   text-decoration: none;
   &:hover {
     text-decoration: underline;
   }
-}
\ No newline at end of file
+}
diff --git a/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss b/dolphinscheduler-ui-next/src/views/resource/index.module.scss
similarity index 82%
copy from dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss
copy to dolphinscheduler-ui-next/src/views/resource/index.module.scss
index 4ec0732..3f76f2a 100644
--- a/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss
+++ b/dolphinscheduler-ui-next/src/views/resource/index.module.scss
@@ -15,11 +15,15 @@
  * limitations under the License.
  */
 
+.container {
+  > .item {
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
 
-.links {
-  color: #2080f0;
-  text-decoration: none;
-  &:hover {
-    text-decoration: underline;
+    > .label {
+      display: inline-block;
+      width: 100px;
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss b/dolphinscheduler-ui-next/src/views/resource/index.tsx
similarity index 83%
copy from dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss
copy to dolphinscheduler-ui-next/src/views/resource/index.tsx
index 4ec0732..4112215 100644
--- a/dolphinscheduler-ui-next/src/views/resource/file/table/index.module.scss
+++ b/dolphinscheduler-ui-next/src/views/resource/index.tsx
@@ -15,11 +15,14 @@
  * limitations under the License.
  */
 
+import { defineComponent } from 'vue'
 
-.links {
-  color: #2080f0;
-  text-decoration: none;
-  &:hover {
-    text-decoration: underline;
+const resource = defineComponent({
+  name: 'resource',
+  setup() {},
+  render() {
+    return {}
   }
-}
\ No newline at end of file
+})
+
+export default resource
diff --git a/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/components/form-modal.tsx b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/components/form-modal.tsx
new file mode 100644
index 0000000..d5a826c
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/components/form-modal.tsx
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent, PropType, toRefs, onMounted, ref, toRaw } from 'vue'
+import { NForm, NFormItem, NInput, NSelect } from 'naive-ui'
+import { useForm } from '../use-form'
+import Modal from '@/components/modal'
+import { createTaskGroup, updateTaskGroup } from '@/service/modules/task-group'
+import { queryAllProjectList } from '@/service/modules/projects'
+
+const props = {
+  show: {
+    type: Boolean as PropType<boolean>,
+    default: false
+  },
+  data: {
+    type: Object as PropType<any>
+  },
+  status: {
+    type: Number as PropType<number>,
+    default: 0
+  }
+}
+
+const FormModal = defineComponent({
+  name: 'FormModal',
+  props,
+  emits: ['confirm', 'cancel'],
+  setup(props, { emit }) {
+    const { state, t } = useForm()
+    const projectOptions = ref([])
+
+    onMounted(() => {
+      queryAllProjectList().then((res: any) => {
+        res.map((item) => {
+          projectOptions.value.push({ label: item.name, value: item.code })
+        })
+      })
+      if (props.status === 1) {
+        state.formData.id = props.data.id
+        state.formData.name = props.data.name
+        state.formData.projectCode = props.data.projectCode
+        state.formData.groupSize = props.data.groupSize
+        state.formData.status = props.data.status
+        state.formData.description = props.data.description
+      } else {
+        state.formData.groupSize = 10
+      }
+    })
+
+    const onConfirm = () => {
+      ;(props.status === 1
+        ? updateTaskGroup(state.formData)
+        : createTaskGroup(state.formData)
+      ).then(() => {
+        emit('confirm')
+      })
+    }
+
+    const onCancel = () => {
+      state.formData.projectCode = 0
+      state.formData.description = ''
+      emit('cancel')
+    }
+
+    return { ...toRefs(state), t, onConfirm, onCancel, projectOptions }
+  },
+  render() {
+    const { t, onConfirm, onCancel, show, status, projectOptions } = this
+    return (
+      <Modal
+        title={
+          status === 0
+            ? t('resource.task_group_option.create')
+            : t('resource.task_group_option.edit')
+        }
+        show={show}
+        onConfirm={onConfirm}
+        onCancel={onCancel}
+        confirmDisabled={
+          !this.formData.name ||
+          !this.formData.groupSize ||
+          !this.formData.description
+        }
+      >
+        <NForm rules={this.rules} ref='formRef'>
+          <NFormItem label={t('resource.task_group_option.name')} path='name'>
+            <NInput
+              v-model={[this.formData.name, 'value']}
+              placeholder={t('resource.task_group_option.please_enter_name')}
+            />
+          </NFormItem>
+          <NFormItem
+            label={t('resource.task_group_option.project_name')}
+            path='projectCode'
+          >
+            <NSelect
+              options={projectOptions}
+              v-model={[this.formData.projectCode, 'value']}
+              placeholder={t(
+                'resource.task_group_option.please_select_project'
+              )}
+            />
+          </NFormItem>
+          <NFormItem
+            label={t('resource.task_group_option.resource_pool_size')}
+            path='groupSize'
+          >
+            <NInput
+              v-model={[this.formData.groupSize, 'value']}
+              placeholder={t(
+                'resource.task_group_option.please_enter_resource_pool_size'
+              )}
+            />
+          </NFormItem>
+          <NFormItem
+            label={t('resource.task_group_option.desc')}
+            path='description'
+          >
+            <NInput
+              v-model={[this.formData.description, 'value']}
+              type='textarea'
+              placeholder={t('resource.task_group_option.please_enter_desc')}
+            />
+          </NFormItem>
+        </NForm>
+      </Modal>
+    )
+  }
+})
+
+export default FormModal
diff --git a/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/components/table-action.tsx b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/components/table-action.tsx
new file mode 100644
index 0000000..d236eec
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/components/table-action.tsx
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent, PropType } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { NSpace, NTooltip, NButton, NIcon, NSwitch } from 'naive-ui'
+import { EditOutlined, UnorderedListOutlined } from '@vicons/antd'
+import type {
+  TaskGroupIdReq,
+  TaskGroup
+} from '@/service/modules/task-group/types'
+import { startTaskGroup, closeTaskGroup } from '@/service/modules/task-group'
+
+interface ItemRow extends TaskGroup {
+  projectList: []
+}
+
+const props = {
+  row: {
+    type: Object as PropType<ItemRow>,
+    default: {}
+  }
+}
+
+const TableAction = defineComponent({
+  name: 'TableAction',
+  props,
+  emits: ['resetTableData', 'updateItem'],
+  setup(props, { emit }) {
+    const { t } = useI18n()
+
+    const handleEdit = (
+      id: number,
+      name: string,
+      projectCode: number,
+      groupSize: number,
+      description: string,
+      status: number
+    ) => {
+      emit('updateItem', id, name, projectCode, groupSize, description, status)
+    }
+
+    const handleSwitchStatus = (value: number, id: number) => {
+      const params: TaskGroupIdReq = { id: id }
+
+      if (value === 1) {
+        startTaskGroup(params).then(() => {
+          emit('resetTableData')
+        })
+      } else if (value === 0) {
+        closeTaskGroup(params).then(() => {
+          emit('resetTableData')
+        })
+      }
+    }
+
+    const handleViewQueue = (id: number) => {}
+
+    return { t, handleEdit, handleViewQueue, handleSwitchStatus }
+  },
+  render() {
+    const { t, handleEdit, handleViewQueue, handleSwitchStatus } = this
+
+    return (
+      <NSpace>
+        <NTooltip trigger={'hover'}>
+          {{
+            default: () => t('resource.task_group_option.switch_status'),
+            trigger: () => (
+              <NSwitch
+                v-model={[this.row.status, 'value']}
+                checkedValue={1}
+                uncheckedValue={0}
+                onUpdate:value={(value) =>
+                  handleSwitchStatus(value, this.row.id)
+                }
+              />
+            )
+          }}
+        </NTooltip>
+        <NTooltip trigger={'hover'}>
+          {{
+            default: () => t('resource.task_group_option.edit'),
+            trigger: () => (
+              <NButton
+                size='small'
+                type='info'
+                tag='div'
+                onClick={() =>
+                  handleEdit(
+                    this.row.id,
+                    this.row.name,
+                    this.row.projectCode,
+                    this.row.groupSize,
+                    this.row.description,
+                    this.row.status
+                  )
+                }
+                circle
+              >
+                <NIcon>
+                  <EditOutlined />
+                </NIcon>
+              </NButton>
+            )
+          }}
+        </NTooltip>
+        <NTooltip trigger={'hover'}>
+          {{
+            default: () => t('resource.task_group_option.view_queue'),
+            trigger: () => (
+              <NButton
+                size='small'
+                type='primary'
+                tag='div'
+                onClick={() => handleViewQueue(this.row.id)}
+                circle
+              >
+                <NIcon>
+                  <UnorderedListOutlined />
+                </NIcon>
+              </NButton>
+            )
+          }}
+        </NTooltip>
+      </NSpace>
+    )
+  }
+})
+
+export default TableAction
diff --git a/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/index.module.scss
similarity index 60%
copy from dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss
copy to dolphinscheduler-ui-next/src/views/resource/taskGroupOption/index.module.scss
index f6ce120..3985f52 100644
--- a/dolphinscheduler-ui-next/src/views/monitor/servers/db/index.module.scss
+++ b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/index.module.scss
@@ -15,29 +15,41 @@
  * limitations under the License.
  */
 
-@mixin base {
-  font-size: 100px;
+.toolbar {
   display: flex;
-  justify-content: center;
+  justify-content: space-between;
   align-items: center;
-  min-height: 240px;
+  padding: 0 0 0 0;
+  .left {
+    align-items: center;
+  }
+  .right {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    button {
+      margin-left: 10px;
+    }
+  }
 }
 
-.health {
-  @include base;
-}
-
-.health-success {
-  color: limegreen;
-}
+.table-card {
+  margin-top: 2px;
 
-.health-error {
-  color: indianred;
+  .table-action {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    button {
+      margin: 0 2px 0 0;
+    }
+    div {
+      margin: 0 2px 0 0;
+    }
+  }
+  .pagination {
+    margin-top: 20px;
+    display: flex;
+    justify-content: center;
+  }
 }
-
-.connections {
-  @include base;
-  color: dodgerblue;
-}
-
-
diff --git a/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/index.tsx b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/index.tsx
new file mode 100644
index 0000000..75e99cb
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/index.tsx
@@ -0,0 +1,222 @@
+/*
+ * 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 { ref, defineComponent, toRefs, reactive, onMounted } from 'vue'
+import {
+  NButton,
+  NIcon,
+  NInput,
+  NCard,
+  NDataTable,
+  NSwitch,
+  NPagination,
+  NTooltip
+} from 'naive-ui'
+import Card from '@/components/card'
+import { SearchOutlined } from '@vicons/antd'
+import { useI18n } from 'vue-i18n'
+import styles from './index.module.scss'
+import { useTable } from './use-table'
+import FormModal from './components/form-modal'
+
+const taskGroupOption = defineComponent({
+  name: 'taskGroupOption',
+  setup() {
+    const { t } = useI18n()
+    const { variables, getTableData } = useTable()
+    const showModalRef = ref(false)
+    const modelStatusRef = ref(0)
+
+    const searchParamRef = ref()
+
+    let updateItemData = reactive({
+      id: 0,
+      name: '',
+      projectCode: 0,
+      groupSize: 0,
+      status: 1,
+      description: ''
+    })
+
+    const requestData = () => {
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo: variables.page,
+        name: variables.name
+      })
+    }
+
+    const resetTableData = () => {
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo: variables.page,
+        name: variables.name
+      })
+    }
+
+    const onCancel = () => {
+      showModalRef.value = false
+    }
+
+    const onConfirm = () => {
+      showModalRef.value = false
+      updateItemData = {
+        id: 0,
+        name: '',
+        projectCode: 0,
+        groupSize: 0,
+        status: 1,
+        description: ''
+      }
+      resetTableData()
+    }
+
+    const onUpdatePageSize = () => {
+      variables.page = 1
+      resetTableData()
+    }
+
+    const updateItem = (
+      id: number,
+      name: string,
+      projectCode: number,
+      groupSize: number,
+      description: string
+    ) => {
+      modelStatusRef.value = 1
+      showModalRef.value = true
+      updateItemData.id = id
+      updateItemData.name = name
+      updateItemData.projectCode = projectCode
+      updateItemData.groupSize = groupSize
+      updateItemData.description = description
+    }
+
+    const onSearch = () => {
+      resetTableData()
+    }
+
+    const onCreate = () => {
+      modelStatusRef.value = 0
+      showModalRef.value = true
+    }
+
+    onMounted(() => {
+      requestData()
+    })
+
+    return {
+      ...toRefs(variables),
+      t,
+      onCreate,
+      onSearch,
+      searchParamRef,
+      resetTableData,
+      onUpdatePageSize,
+      updateItem,
+      showModalRef,
+      modelStatusRef,
+      onCancel,
+      onConfirm,
+      updateItemData
+    }
+  },
+  render() {
+    const {
+      t,
+      showModalRef,
+      modelStatusRef,
+      onCancel,
+      onConfirm,
+      updateItemData,
+      resetTableData,
+      onUpdatePageSize,
+      updateItem,
+      onSearch
+    } = this
+
+    const { columns } = useTable(updateItem, resetTableData)
+
+    return (
+      <div>
+        <NCard>
+          <div class={styles.toolbar}>
+            <div class={styles.left}>
+              <NButton
+                size='small'
+                type={'primary'}
+                onClick={() => this.onCreate()}
+              >
+                {t('resource.task_group_option.create')}
+              </NButton>
+            </div>
+            <div class={styles.right}>
+              <NInput
+                size='small'
+                v-model={[this.name, 'value']}
+                placeholder={t(
+                  'resource.task_group_option.please_enter_keywords'
+                )}
+              ></NInput>
+              <NButton size='small' type='primary' onClick={onSearch}>
+                <NIcon>
+                  <SearchOutlined />
+                </NIcon>
+              </NButton>
+            </div>
+          </div>
+        </NCard>
+        <Card
+          class={styles['table-card']}
+          title={t('resource.task_group_option.option')}
+        >
+          <div>
+            <NDataTable
+              columns={columns}
+              size={'small'}
+              data={this.tableData}
+              striped
+            />
+            <div class={styles.pagination}>
+              <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={resetTableData}
+                onUpdatePageSize={onUpdatePageSize}
+              />
+            </div>
+          </div>
+        </Card>
+        {showModalRef && (
+          <FormModal
+            show={showModalRef}
+            onCancel={onCancel}
+            onConfirm={onConfirm}
+            data={updateItemData}
+            status={modelStatusRef}
+          />
+        )}
+      </div>
+    )
+  }
+})
+
+export default taskGroupOption
diff --git a/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/use-form.ts b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/use-form.ts
new file mode 100644
index 0000000..fcdc49d
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/use-form.ts
@@ -0,0 +1,58 @@
+/*
+ * 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 { useI18n } from 'vue-i18n'
+import { reactive, ref } from 'vue'
+import type { FormRules } from 'naive-ui'
+
+export function useForm() {
+  const { t } = useI18n()
+
+  const state = reactive({
+    formRef: ref(),
+    formData: {
+      id: 0,
+      name: '',
+      projectCode: 0,
+      groupSize: 0,
+      status: 1,
+      description: ''
+    },
+    rules: {
+      name: {
+        required: true,
+        trigger: ['input', 'blur'],
+        validator() {
+          if (state.formData.name === '') {
+            return new Error(t('resource.task_group_option.please_enter_name'))
+          }
+        }
+      },
+      description: {
+        required: true,
+        trigger: ['input', 'blur'],
+        validator() {
+          if (state.formData.description === '') {
+            return new Error(t('resource.task_group_option.please_enter_desc'))
+          }
+        }
+      }
+    } as FormRules
+  })
+
+  return { state, t }
+}
diff --git a/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/use-table.ts b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/use-table.ts
new file mode 100644
index 0000000..3c85c91
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/taskGroupOption/use-table.ts
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { h, reactive, ref } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useAsyncState } from '@vueuse/core'
+import { format } from 'date-fns'
+import { useRouter } from 'vue-router'
+import type { Router } from 'vue-router'
+import type { TableColumns } from 'naive-ui/es/data-table/src/interface'
+import { queryTaskGroupListPaging } from '@/service/modules/task-group'
+import { queryAllProjectList } from '@/service/modules/projects'
+import TableAction from './components/table-action'
+import _ from 'lodash'
+
+export function useTable(
+  updateItem = (
+    id: number,
+    name: string,
+    projectCode: number,
+    groupSize: number,
+    description: string,
+    status: number
+  ): void => {},
+  resetTableData = () => {}
+) {
+  const { t } = useI18n()
+  const router: Router = useRouter()
+
+  const columns: TableColumns<any> = [
+    { title: t('resource.task_group_option.id'), key: 'index' },
+    { title: t('resource.task_group_option.name'), key: 'name' },
+    { title: t('resource.task_group_option.project_name'), key: 'projectName' },
+    {
+      title: t('resource.task_group_option.resource_pool_size'),
+      key: 'groupSize'
+    },
+    {
+      title: t('resource.task_group_option.resource_used_pool_size'),
+      key: 'useSize'
+    },
+    { title: t('resource.task_group_option.desc'), key: 'description' },
+    { title: t('resource.task_group_option.create_time'), key: 'createTime' },
+    { title: t('resource.task_group_option.update_time'), key: 'updateTime' },
+    {
+      title: t('resource.task_group_option.actions'),
+      key: 'actions',
+      width: 150,
+      render: (row: any) =>
+        h(TableAction, {
+          row,
+          onResetTableData: () => {
+            if (variables.page > 1 && variables.tableData.length === 1) {
+              variables.page -= 1
+            }
+            resetTableData()
+          },
+          onUpdateItem: (
+            id: number,
+            name: string,
+            projectCode: number,
+            groupSize: number,
+            description: string,
+            status: number
+          ) => {
+            updateItem(id, name, projectCode, groupSize, description, status)
+          }
+        })
+    }
+  ]
+
+  const variables = reactive({
+    tableData: [],
+    page: ref(1),
+    pageSize: ref(10),
+    name: ref(null),
+    totalPage: ref(1)
+  })
+
+  const getTableData = (params: any) => {
+    const { state } = useAsyncState(
+      Promise.all([
+        queryTaskGroupListPaging(params),
+        queryAllProjectList()
+      ]).then((values) => {
+        variables.totalPage = values[0].totalPage
+        variables.tableData = values[0].totalList.map((item, index) => {
+          item.projectName = _.find(values[1], { code: item.projectCode }).name
+          item.createTime = format(
+            new Date(item.createTime),
+            'yyyy-MM-dd HH:mm:ss'
+          )
+          item.updateTime = format(
+            new Date(item.updateTime),
+            'yyyy-MM-dd HH:mm:ss'
+          )
+          return {
+            index: index + 1,
+            ...item
+          }
+        }) as any
+      }),
+      {}
+    )
+    return state
+  }
+
+  return { getTableData, variables, columns }
+}