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

[dolphinscheduler] branch dev updated: [Feature][UI Next] Security alarm group manage (#8069)

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

kirs 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 ec7898d  [Feature][UI Next] Security alarm group manage (#8069)
ec7898d is described below

commit ec7898deea79f0fd63cdb5e37552fcbb5c935c1a
Author: songjianet <17...@qq.com>
AuthorDate: Sun Jan 16 19:17:55 2022 +0800

    [Feature][UI Next] Security alarm group manage (#8069)
    
    * [Feature][UI Next] Add security alarm group manage.
    
    * [Feature][UI Next] Add security alarm group manage license.
---
 dolphinscheduler-ui-next/pnpm-lock.yaml            |   8 +-
 .../src/locales/modules/en_US.ts                   |  18 ++
 .../src/locales/modules/zh_CN.ts                   |  19 +++
 .../src/router/modules/security.ts                 |   8 +
 .../src/service/modules/alert-group/index.ts       |   7 +-
 .../src/service/modules/alert-group/types.ts       |  21 ++-
 .../src/service/modules/alert-plugin/types.ts      |  13 +-
 .../datasource/datasource-list/json-highlight.tsx  |   4 +-
 .../datasource/datasource-list/use-columns.ts      |   3 +-
 .../components/alert-group-modal.tsx               | 166 +++++++++++++++++++
 .../alarm-group-manage/components/use-modal.ts     | 130 +++++++++++++++
 .../security/alarm-group-manage/index.module.scss} |  36 ++--
 .../views/security/alarm-group-manage/index.tsx    | 158 ++++++++++++++++++
 .../views/security/alarm-group-manage/use-table.ts | 182 +++++++++++++++++++++
 14 files changed, 749 insertions(+), 24 deletions(-)

diff --git a/dolphinscheduler-ui-next/pnpm-lock.yaml b/dolphinscheduler-ui-next/pnpm-lock.yaml
index a20adb7..d25d5ec 100644
--- a/dolphinscheduler-ui-next/pnpm-lock.yaml
+++ b/dolphinscheduler-ui-next/pnpm-lock.yaml
@@ -29,13 +29,14 @@ specifiers:
   '@vueuse/core': ^7.5.3
   axios: ^0.24.0
   dart-sass: ^1.25.0
-  date-fns: ^2.28.0
+  date-fns: ^2.27.0
   echarts: ^5.2.2
   eslint: ^8.6.0
   eslint-config-prettier: ^8.3.0
   eslint-plugin-prettier: ^4.0.0
   eslint-plugin-vue: ^8.2.0
   lodash: ^4.17.21
+  monaco-editor: ^0.31.1
   naive-ui: 2.23.2
   nprogress: ^0.2.0
   pinia: ^2.0.9
@@ -60,6 +61,7 @@ dependencies:
   date-fns: 2.28.0
   echarts: 5.2.2
   lodash: 4.17.21
+  monaco-editor: 0.31.1
   naive-ui: 2.23.2_vue@3.2.26
   nprogress: 0.2.0
   pinia: 2.0.9_typescript@4.5.4+vue@3.2.26
@@ -2263,6 +2265,10 @@ packages:
     hasBin: true
     dev: true
 
+  /monaco-editor/0.31.1:
+    resolution: {integrity: sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==}
+    dev: false
+
   /ms/2.0.0:
     resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=}
     dev: true
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index 92d74e2..8216a03 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -281,6 +281,23 @@ const security = {
     edit: 'Edit',
     delete: 'Delete'
   },
+  alarm_group: {
+    create_alarm_group: 'Create Alarm Group',
+    edit_alarm_group: 'Edit Alarm Group',
+    search_tips: 'Please enter keywords',
+    alert_group_name_tips: 'Please enter your alert group name',
+    alarm_plugin_instance: 'Alarm Plugin Instance',
+    alarm_plugin_instance_tips: 'Please select alert plugin instance',
+    alarm_group_description_tips: 'Please enter your alarm group description',
+    alert_group_name: 'Alert Group Name',
+    alarm_group_description: 'Alarm Group Description',
+    create_time: 'Create Time',
+    update_time: 'Update Time',
+    operation: 'Operation',
+    delete_confirm: 'Delete?',
+    edit: 'Edit',
+    delete: 'Delete'
+  },
   yarn_queue: {
     create_queue: 'Create Queue',
     edit_queue: 'Edit Queue',
@@ -314,6 +331,7 @@ const security = {
     worker_group_tips: 'Please select worker group'
   }
 }
+
 const datasource = {
   datasource: 'DataSource',
   create_datasource: 'Create DataSource',
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index f15d13d..2fc5a88 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -281,6 +281,24 @@ const security = {
     edit: '编辑',
     delete: '删除'
   },
+  alarm_group: {
+    create_alarm_group: '创建告警组',
+    edit_alarm_group: '编辑告警组',
+    search_tips: '请输入关键词',
+    alert_group_name_tips: '请输入告警组名称',
+    alarm_plugin_instance: '告警组实例',
+    alarm_plugin_instance_tips: '请选择告警组实例',
+    alarm_group_description_tips: '请输入告警组描述',
+    alert_group_name: '告警组名称',
+    alarm_group_description: '告警组描述',
+    create_time: '创建时间',
+    update_time: '更新时间',
+    actions: '操作',
+    operation: '操作',
+    delete_confirm: '确定删除吗?',
+    edit: '编辑',
+    delete: '删除'
+  },
   yarn_queue: {
     create_queue: '创建队列',
     edit_queue: '编辑队列',
@@ -314,6 +332,7 @@ const security = {
     worker_group_tips: '请选择Worker分组'
   }
 }
+
 const datasource = {
   datasource: '数据源',
   create_datasource: '创建数据源',
diff --git a/dolphinscheduler-ui-next/src/router/modules/security.ts b/dolphinscheduler-ui-next/src/router/modules/security.ts
index b830448..6677a7c 100644
--- a/dolphinscheduler-ui-next/src/router/modules/security.ts
+++ b/dolphinscheduler-ui-next/src/router/modules/security.ts
@@ -46,6 +46,14 @@ export default {
       }
     },
     {
+      path: '/security/alarm-group-manage',
+      name: 'alarm-group-manage',
+      component: components['alarm-group-manage'],
+      meta: {
+        title: '告警组管理'
+      }
+    },
+    {
       path: '/security/yarn-queue-manage',
       name: 'yarn-queue-manage',
       component: components['yarn-queue-manage'],
diff --git a/dolphinscheduler-ui-next/src/service/modules/alert-group/index.ts b/dolphinscheduler-ui-next/src/service/modules/alert-group/index.ts
index 437bc28..b9da629 100644
--- a/dolphinscheduler-ui-next/src/service/modules/alert-group/index.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/alert-group/index.ts
@@ -59,7 +59,7 @@ export function verifyGroupName(params: GroupNameReq): any {
 
 export function updateAlertGroup(data: GroupReq, id: IdReq): any {
   return axios({
-    url: `/alert-groups/${id}`,
+    url: `/alert-groups/${id.id}`,
     method: 'put',
     data
   })
@@ -67,7 +67,8 @@ export function updateAlertGroup(data: GroupReq, id: IdReq): any {
 
 export function delAlertGroupById(id: IdReq): any {
   return axios({
-    url: `/alert-groups/${id}`,
-    method: 'delete'
+    url: `/alert-groups/${id.id}`,
+    method: 'delete',
+    params: id
   })
 }
diff --git a/dolphinscheduler-ui-next/src/service/modules/alert-group/types.ts b/dolphinscheduler-ui-next/src/service/modules/alert-group/types.ts
index 640ecd3..e840c7b 100644
--- a/dolphinscheduler-ui-next/src/service/modules/alert-group/types.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/alert-group/types.ts
@@ -34,4 +34,23 @@ interface GroupReq extends GroupNameReq {
   description?: string
 }
 
-export { ListReq, GroupNameReq, IdReq, GroupReq }
+interface AlarmGroupItem {
+  id: number
+  groupName: string
+  alertInstanceIds: string
+  description: string
+  createTime: string
+  updateTime: string
+  createUserId: number
+}
+
+interface AlarmGroupRes {
+  totalList: AlarmGroupItem[]
+  total: number
+  totalPage: number
+  pageSize: number
+  currentPage: number
+  start: number
+}
+
+export { ListReq, GroupNameReq, IdReq, GroupReq, AlarmGroupItem, AlarmGroupRes }
diff --git a/dolphinscheduler-ui-next/src/service/modules/alert-plugin/types.ts b/dolphinscheduler-ui-next/src/service/modules/alert-plugin/types.ts
index 664ddaa..74d8905 100644
--- a/dolphinscheduler-ui-next/src/service/modules/alert-plugin/types.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/alert-plugin/types.ts
@@ -41,10 +41,21 @@ interface UpdatePluginInstanceReq {
   pluginInstanceParams: string
 }
 
+interface AlertPluginItem {
+  id: number
+  pluginDefineId: number
+  instanceName: string
+  pluginInstanceParams: string
+  createTime: string
+  updateTime: string
+  alertPluginName: string
+}
+
 export {
   ListReq,
   PluginInstanceReq,
   InstanceNameReq,
   IdReq,
-  UpdatePluginInstanceReq
+  UpdatePluginInstanceReq,
+  AlertPluginItem
 }
diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx
index 0dbf5fc..162bcd6 100644
--- a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx
+++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx
@@ -32,7 +32,9 @@ const JsonHighlight = defineComponent({
   props,
   render(props: { rowData: { connectionParams: string } }) {
     return (
-      <pre class={styles['json-highlight']}>{syntaxHighlight(props.rowData.connectionParams)}</pre>
+      <pre class={styles['json-highlight']}>
+        {syntaxHighlight(props.rowData.connectionParams)}
+      </pre>
     )
   }
 })
diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts
index a78c038..7ff3afd 100644
--- a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts
+++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts
@@ -63,8 +63,7 @@ export function useColumns(onCallback: Function) {
                   default: () => t('datasource.click_to_view')
                 }
               ),
-            default: () =>
-              h(JsonHighlight, { rowData })
+            default: () => h(JsonHighlight, { rowData })
           }
         )
       }
diff --git a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alert-group-modal.tsx b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alert-group-modal.tsx
new file mode 100644
index 0000000..ffe457a
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alert-group-modal.tsx
@@ -0,0 +1,166 @@
+/*
+ * 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, watch } from 'vue'
+import Modal from '@/components/modal'
+import { NForm, NFormItem, NInput, NSelect } from 'naive-ui'
+import { useModal } from './use-modal'
+import { useI18n } from 'vue-i18n'
+
+const AlertGroupModal = defineComponent({
+  name: 'YarnQueueModal',
+  props: {
+    showModalRef: {
+      type: Boolean as PropType<boolean>,
+      default: false
+    },
+    statusRef: {
+      type: Number as PropType<number>,
+      default: 0
+    },
+    row: {
+      type: Object as PropType<any>,
+      default: {}
+    }
+  },
+  emits: ['cancelModal', 'confirmModal'],
+  setup(props, ctx) {
+    const { variables, handleValidate, getListData } = useModal(props, ctx)
+    const { t } = useI18n()
+
+    const cancelModal = () => {
+      if (props.statusRef === 0) {
+        variables.model.groupName = ''
+        variables.model.alertInstanceIds = []
+        variables.model.description = ''
+      }
+      ctx.emit('cancelModal', props.showModalRef)
+    }
+
+    const confirmModal = () => {
+      handleValidate(props.statusRef)
+    }
+
+    watch(
+      () => props.showModalRef,
+      () => {
+        props.showModalRef && getListData()
+      }
+    )
+
+    watch(
+      () => props.statusRef,
+      () => {
+        if (props.statusRef === 0) {
+          variables.model.groupName = ''
+          variables.model.alertInstanceIds = []
+          variables.model.description = ''
+        } else {
+          variables.model.id = props.row.id
+          variables.model.groupName = props.row.groupName
+          variables.model.alertInstanceIds = props.row.alertInstanceIds
+            .split(',')
+            .map((item: string) => Number(item))
+          variables.model.description = props.row.description
+        }
+      }
+    )
+
+    watch(
+      () => props.row,
+      () => {
+        variables.model.id = props.row.id
+        variables.model.groupName = props.row.groupName
+        variables.model.alertInstanceIds = props.row.alertInstanceIds
+          .split(',')
+          .map((item: string) => Number(item))
+        variables.model.description = props.row.description
+      }
+    )
+
+    return { t, ...toRefs(variables), cancelModal, confirmModal }
+  },
+  render() {
+    const { t } = this
+    return (
+      <div>
+        <Modal
+          title={
+            this.statusRef === 0
+              ? t('security.alarm_group.create_alarm_group')
+              : t('security.alarm_group.edit_alarm_group')
+          }
+          show={this.showModalRef}
+          onCancel={this.cancelModal}
+          onConfirm={this.confirmModal}
+          confirmDisabled={
+            !this.model.groupName || this.model.alertInstanceIds.length < 1
+          }
+        >
+          {{
+            default: () => (
+              <NForm
+                model={this.model}
+                rules={this.rules}
+                ref='alertGroupFormRef'
+              >
+                <NFormItem
+                  label={t('security.alarm_group.alert_group_name')}
+                  path='groupName'
+                >
+                  <NInput
+                    placeholder={t(
+                      'security.alarm_group.alert_group_name_tips'
+                    )}
+                    v-model={[this.model.groupName, 'value']}
+                  />
+                </NFormItem>
+                <NFormItem
+                  label={t('security.alarm_group.alarm_plugin_instance')}
+                  path='alertInstanceIds'
+                >
+                  <NSelect
+                    multiple
+                    placeholder={t(
+                      'security.alarm_group.alarm_plugin_instance_tips'
+                    )}
+                    options={this.model.generalOptions}
+                    v-model={[this.model.alertInstanceIds, 'value']}
+                  />
+                </NFormItem>
+                <NFormItem
+                  label={t('security.alarm_group.alarm_group_description')}
+                  path='description'
+                >
+                  <NInput
+                    type='textarea'
+                    placeholder={t(
+                      'security.alarm_group.alarm_group_description_tips'
+                    )}
+                    v-model={[this.model.description, 'value']}
+                  />
+                </NFormItem>
+              </NForm>
+            )
+          }}
+        </Modal>
+      </div>
+    )
+  }
+})
+
+export default AlertGroupModal
diff --git a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/use-modal.ts b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/use-modal.ts
new file mode 100644
index 0000000..5cbadf0
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/use-modal.ts
@@ -0,0 +1,130 @@
+/*
+ * 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, ref, SetupContext } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useAsyncState } from '@vueuse/core'
+import { queryAlertPluginInstanceList } from '@/service/modules/alert-plugin'
+import {
+  verifyGroupName,
+  createAlertGroup,
+  updateAlertGroup
+} from '@/service/modules/alert-group'
+import type { AlertPluginItem } from '@/service/modules/alert-plugin/types'
+
+export function useModal(
+  props: any,
+  ctx: SetupContext<('cancelModal' | 'confirmModal')[]>
+) {
+  const { t } = useI18n()
+
+  const variables = reactive({
+    alertGroupFormRef: ref(),
+    model: {
+      id: ref<number>(-1),
+      groupName: ref(''),
+      alertInstanceIds: ref<Array<number>>([]),
+      description: ref(''),
+      generalOptions: []
+    },
+    rules: {
+      groupName: {
+        required: true,
+        trigger: ['input', 'blur'],
+        validator() {
+          if (variables.model.groupName === '') {
+            return new Error(t('security.alarm_group.alert_group_name_tips'))
+          }
+        }
+      },
+      alertInstanceIds: {
+        required: true,
+        trigger: ['input', 'blur'],
+        validator() {
+          if (variables.model.alertInstanceIds.length < 1) {
+            return new Error(
+              t('security.alarm_group.alarm_plugin_instance_tips')
+            )
+          }
+        }
+      }
+    }
+  })
+
+  const getListData = () => {
+    const { state } = useAsyncState(
+      queryAlertPluginInstanceList().then((res: Array<AlertPluginItem>) => {
+        variables.model.generalOptions = res.map(
+          (item): { label: string; value: number } => {
+            return {
+              label: item.instanceName,
+              value: item.id
+            }
+          }
+        ) as any
+      }),
+      {}
+    )
+
+    return state
+  }
+
+  const handleValidate = (statusRef: number) => {
+    variables.alertGroupFormRef.validate((errors: any) => {
+      if (!errors) {
+        statusRef === 0 ? submitAlertGroupModal() : updateAlertGroupModal()
+      } else {
+        return
+      }
+    })
+  }
+
+  const submitAlertGroupModal = () => {
+    verifyGroupName({ groupName: variables.model.groupName }).then(() => {
+      const data = {
+        groupName: variables.model.groupName,
+        alertInstanceIds: variables.model.alertInstanceIds.toString(),
+        description: variables.model.description
+      }
+
+      createAlertGroup(data).then(() => {
+        variables.model.groupName = ''
+        variables.model.alertInstanceIds = []
+        variables.model.description = ''
+        ctx.emit('confirmModal', props.showModalRef)
+      })
+    })
+  }
+
+  const updateAlertGroupModal = () => {
+    const data = {
+      groupName: variables.model.groupName,
+      alertInstanceIds: variables.model.alertInstanceIds.toString(),
+      description: variables.model.description
+    }
+
+    updateAlertGroup(data, { id: variables.model.id }).then(() => {
+      ctx.emit('confirmModal', props.showModalRef)
+    })
+  }
+
+  return {
+    variables,
+    handleValidate,
+    getListData
+  }
+}
diff --git a/dolphinscheduler-ui-next/src/service/modules/alert-group/types.ts b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.module.scss
similarity index 69%
copy from dolphinscheduler-ui-next/src/service/modules/alert-group/types.ts
copy to dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.module.scss
index 640ecd3..de6cf70 100644
--- a/dolphinscheduler-ui-next/src/service/modules/alert-group/types.ts
+++ b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.module.scss
@@ -15,23 +15,29 @@
  * limitations under the License.
  */
 
-interface ListReq {
-  pageNo: number
-  pageSize: number
-  searchVal?: string
-}
+.search-card {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
 
-interface GroupNameReq {
-  groupName: string
-}
+  .box {
+    display: flex;
+    justify-content: flex-end;
+    align-items: center;
+    width: 300px;
 
-interface IdReq {
-  id: number
+    button {
+      margin-left: 10px;
+    }
+  }
 }
 
-interface GroupReq extends GroupNameReq {
-  alertInstanceIds: string
-  description?: string
-}
+.table-card {
+  margin-top: 8px;
 
-export { ListReq, GroupNameReq, IdReq, GroupReq }
+  .pagination {
+    margin-top: 20px;
+    display: flex;
+    justify-content: center;
+  }
+}
diff --git a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx
new file mode 100644
index 0000000..4ee81d6
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx
@@ -0,0 +1,158 @@
+/*
+ * 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 } from 'vue'
+import {
+  NButton,
+  NCard,
+  NDataTable,
+  NIcon,
+  NInput,
+  NPagination
+} from 'naive-ui'
+import { SearchOutlined } from '@vicons/antd'
+import { useI18n } from 'vue-i18n'
+import { useTable } from './use-table'
+import Card from '@/components/card'
+import AlertGroupModal from './components/alert-group-modal'
+import styles from './index.module.scss'
+
+const alarmGroupManage = defineComponent({
+  name: 'alarm-group-manage',
+  setup() {
+    const { t } = useI18n()
+    const { variables, getTableData, createColumns } = useTable()
+
+    const requestData = () => {
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo: variables.page,
+        searchVal: variables.searchVal
+      })
+    }
+
+    const onUpdatePageSize = () => {
+      variables.page = 1
+      requestData()
+    }
+
+    const onSearch = () => {
+      variables.page = 1
+      requestData()
+    }
+
+    const handleModalChange = () => {
+      variables.showModalRef = true
+      variables.statusRef = 0
+    }
+
+    const onCancelModal = () => {
+      variables.showModalRef = false
+    }
+
+    const onConfirmModal = () => {
+      variables.showModalRef = false
+      requestData()
+    }
+
+    onMounted(() => {
+      createColumns(variables)
+      requestData()
+    })
+
+    watch(useI18n().locale, () => {
+      createColumns(variables)
+    })
+
+    return {
+      t,
+      ...toRefs(variables),
+      requestData,
+      onCancelModal,
+      onConfirmModal,
+      onUpdatePageSize,
+      handleModalChange,
+      onSearch
+    }
+  },
+  render() {
+    const {
+      t,
+      requestData,
+      onUpdatePageSize,
+      onCancelModal,
+      onConfirmModal,
+      handleModalChange,
+      onSearch
+    } = this
+
+    return (
+      <div>
+        <NCard>
+          <div class={styles['search-card']}>
+            <div>
+              <NButton size='small' type='primary' onClick={handleModalChange}>
+                {t('security.alarm_group.create_alarm_group')}
+              </NButton>
+            </div>
+            <div class={styles.box}>
+              <NInput
+                size='small'
+                clearable
+                v-model={[this.searchVal, 'value']}
+                placeholder={t('security.alarm_group.search_tips')}
+              />
+              <NButton size='small' type='primary' onClick={onSearch}>
+                {{
+                  icon: () => (
+                    <NIcon>
+                      <SearchOutlined />
+                    </NIcon>
+                  )
+                }}
+              </NButton>
+            </div>
+          </div>
+        </NCard>
+        <Card class={styles['table-card']}>
+          <NDataTable columns={this.columns} data={this.tableData} />
+          <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={requestData}
+              onUpdatePageSize={onUpdatePageSize}
+            />
+          </div>
+        </Card>
+        <AlertGroupModal
+          showModalRef={this.showModalRef}
+          statusRef={this.statusRef}
+          row={this.row}
+          onCancelModal={onCancelModal}
+          onConfirmModal={onConfirmModal}
+        />
+      </div>
+    )
+  }
+})
+
+export default alarmGroupManage
diff --git a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/use-table.ts b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/use-table.ts
new file mode 100644
index 0000000..a77dcf9
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/use-table.ts
@@ -0,0 +1,182 @@
+/*
+ * 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 { useAsyncState } from '@vueuse/core'
+import { reactive, h, ref } from 'vue'
+import { format } from 'date-fns'
+import { NButton, NPopconfirm, NSpace, NTooltip } from 'naive-ui'
+import { useI18n } from 'vue-i18n'
+import {
+  queryAlertGroupListPaging,
+  delAlertGroupById
+} from '@/service/modules/alert-group'
+import { DeleteOutlined, EditOutlined } from '@vicons/antd'
+import type { AlarmGroupRes } from '@/service/modules/alert-group/types'
+
+export function useTable() {
+  const { t } = useI18n()
+
+  const handleEdit = (row: any) => {
+    variables.showModalRef = true
+    variables.statusRef = 1
+    variables.row = row
+  }
+
+  const createColumns = (variables: any) => {
+    variables.columns = [
+      {
+        title: '#',
+        key: 'index'
+      },
+      {
+        title: t('security.alarm_group.alert_group_name'),
+        key: 'groupName'
+      },
+      {
+        title: t('security.alarm_group.alarm_group_description'),
+        key: 'description'
+      },
+      {
+        title: t('security.alarm_group.create_time'),
+        key: 'createTime'
+      },
+      {
+        title: t('security.alarm_group.update_time'),
+        key: 'updateTime'
+      },
+      {
+        title: t('security.alarm_group.operation'),
+        key: 'operation',
+        render(row: any) {
+          return h(NSpace, null, {
+            default: () => [
+              h(
+                NTooltip,
+                {},
+                {
+                  trigger: () =>
+                    h(
+                      NButton,
+                      {
+                        circle: true,
+                        type: 'info',
+                        size: 'small',
+                        onClick: () => {
+                          handleEdit(row)
+                        }
+                      },
+                      {
+                        icon: () => h(EditOutlined)
+                      }
+                    ),
+                  default: () => t('security.alarm_group.edit')
+                }
+              ),
+              h(
+                NPopconfirm,
+                {
+                  onPositiveClick: () => {
+                    handleDelete(row)
+                  }
+                },
+                {
+                  trigger: () =>
+                    h(
+                      NTooltip,
+                      {},
+                      {
+                        trigger: () =>
+                          h(
+                            NButton,
+                            {
+                              circle: true,
+                              type: 'error',
+                              size: 'small'
+                            },
+                            {
+                              icon: () => h(DeleteOutlined)
+                            }
+                          ),
+                        default: () => t('security.alarm_group.delete')
+                      }
+                    ),
+                  default: () => t('security.alarm_group.delete_confirm')
+                }
+              )
+            ]
+          })
+        }
+      }
+    ]
+  }
+
+  const variables = reactive({
+    columns: [],
+    tableData: [],
+    page: ref(1),
+    pageSize: ref(10),
+    searchVal: ref(null),
+    totalPage: ref(1),
+    showModalRef: ref(false),
+    statusRef: ref(0),
+    row: {}
+  })
+
+  const handleDelete = (row: any) => {
+    delAlertGroupById({ id: row.id }).then(() => {
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo:
+          variables.tableData.length === 1 && variables.page > 1
+            ? variables.page - 1
+            : variables.page,
+        searchVal: variables.searchVal
+      })
+    })
+  }
+
+  const getTableData = (params: any) => {
+    const { state } = useAsyncState(
+      queryAlertGroupListPaging({ ...params }).then((res: AlarmGroupRes) => {
+        variables.tableData = res.totalList.map((item, index) => {
+          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
+        variables.totalPage = res.totalPage
+      }),
+      {}
+    )
+
+    return state
+  }
+
+  return {
+    variables,
+    getTableData,
+    createColumns
+  }
+}