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

gongchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git


The following commit(s) were added to refs/heads/master by this push:
     new 2ffdda8f2 [improve] optimize the monitoring editing form. (#2172)
2ffdda8f2 is described below

commit 2ffdda8f26f06cba5946a75b3de3847c9365b805
Author: Kerwin Bryant <[email protected]>
AuthorDate: Wed Jul 3 14:31:48 2024 +0800

    [improve] optimize the monitoring editing form. (#2172)
    
    Signed-off-by: Kerwin Bryant <[email protected]>
    Co-authored-by: tomsun28 <[email protected]>
---
 .../monitor-edit/monitor-edit.component.html       | 468 +-------------------
 .../monitor/monitor-edit/monitor-edit.component.ts | 161 +------
 .../monitor-form/monitor-form.component.html       | 139 ++++++
 .../monitor-form/monitor-form.component.spec.ts    |  43 ++
 .../monitor/monitor-form/monitor-form.component.ts | 156 +++++++
 .../monitor/monitor-new/monitor-new.component.html | 478 +--------------------
 .../monitor/monitor-new/monitor-new.component.ts   | 200 +--------
 web-app/src/app/routes/monitor/monitor.module.ts   |   2 +
 .../components/form-item/form-item.component.html  | 288 +++++++++++++
 .../components/form-item/form-item.component.less  |   0
 .../form-item/form-item.component.spec.ts          |  43 ++
 .../components/form-item/form-item.component.ts    | 123 ++++++
 web-app/src/app/shared/shared.module.ts            |   9 +-
 13 files changed, 853 insertions(+), 1257 deletions(-)

diff --git 
a/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html 
b/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html
index 25ae21ee7..866094379 100644
--- a/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html
+++ b/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html
@@ -23,457 +23,21 @@
   [guild_link]="'monitor.app.' + monitor.app + '.helpLink' | i18n"
   [icon_name]="'edit'"
 ></app-help-message-show>
-<nz-divider></nz-divider>
-
-<nz-spin [nzSpinning]="isSpinning" [nzTip]="spinningTip" nzSize="large">
-  <div class="-inner-content">
-    <form nz-form #editForm="ngForm">
-      <nz-form-item>
-        <nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" 
[nzTooltipTitle]="'monitor.host.tip' | i18n">
-          {{ hostName ? hostName : ('monitor.host' | i18n) }}
-        </nz-form-label>
-        <nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | 
i18n">
-          <input [(ngModel)]="monitor.host" nz-input name="host" type="text" 
id="host" required [placeholder]="'monitor.host.tip' | i18n" />
-        </nz-form-control>
-      </nz-form-item>
-      <nz-form-item>
-        <nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" 
[nzTooltipTitle]="'monitor.name.tip' | i18n">
-          {{ 'monitor.name' | i18n }}
-        </nz-form-label>
-        <nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | 
i18n">
-          <input [(ngModel)]="monitor.name" nz-input required name="name" 
type="text" id="name" [placeholder]="'monitor.name.tip' | i18n" />
-        </nz-form-control>
-      </nz-form-item>
-
-      <ng-container *ngFor="let paramDefine of paramDefines; let i = index">
-        <nz-form-item *ngIf="params[i].display">
-          <nz-form-label
-            *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-            nzSpan="7"
-            [nzRequired]="paramDefine.required"
-            [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control
-            *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-            nzSpan="8"
-            [nzErrorTip]="'validation.required' | i18n"
-          >
-            <input
-              nz-input
-              [(ngModel)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [type]="paramDefine.type"
-              [id]="paramDefine.field"
-              [placeholder]="paramDefine.placeholder ? paramDefine.placeholder 
: ''"
-            />
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'textarea'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'textarea'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <textarea
-              nz-input
-              [(ngModel)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-              [placeholder]="paramDefine.placeholder ? paramDefine.placeholder 
: ''"
-              rows="8"
-            ></textarea>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'password'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'password'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <app-multi-func-input
-              [placeholder]="paramDefine.placeholder ? paramDefine.placeholder 
: ''"
-              [(value)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-              groupStyle="width: 100%"
-              type="password"
-            />
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'number'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'number'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <nz-input-number
-              [(ngModel)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              [nzMin]="-1000"
-              [nzMax]="65535"
-              [nzStep]="1"
-              [nzPlaceHolder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-            ></nz-input-number>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'boolean'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'boolean'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <nz-switch
-              [(ngModel)]="params[i].paramValue"
-              (ngModelChange)="onParamBooleanChanged($event, 
paramDefine.field)"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-            ></nz-switch>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'radio'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'radio'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <nz-radio-group
-              [(ngModel)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              nzButtonStyle="solid"
-              (ngModelChange)="onDependChanged($event, paramDefine.field)"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-            >
-              <label nz-radio-button [nzValue]="optionItem.value" *ngFor="let 
optionItem of paramDefine.options">
-                {{ optionItem.label }}
-              </label>
-            </nz-radio-group>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'key-value'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'key-value'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <app-key-value-input
-              [(value)]="params[i].paramValue"
-              [id]="paramDefine.field"
-              keyAlias="Header Name"
-              valueAlias="Header Value"
-            ></app-key-value-input>
-          </nz-form-control>
-
-          <nz-form-label
-            *ngIf="paramDefine.type === 'metrics-field'"
-            nzSpan="7"
-            [nzRequired]="paramDefine.required"
-            [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'metrics-field'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-            <app-metrics-field-input
-              [(value)]="params[i].paramValue"
-              [id]="paramDefine.field"
-              [FieldAlias]="'Field'"
-              [UnitAlias]="'Unit'"
-              [TypeAlias]="'Type'"
-            ></app-metrics-field-input>
-          </nz-form-control>
-        </nz-form-item>
-      </ng-container>
-
-      <nz-collapse [nzGhost]="true" style="margin-bottom: 16px">
-        <nz-collapse-panel [nzHeader]="extraColHeader" [nzShowArrow]="false">
-          <ng-container *ngFor="let paramDefine of advancedParamDefines; let i 
= index">
-            <nz-form-item *ngIf="advancedParams[i].display">
-              <nz-form-label
-                *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control
-                *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-                nzSpan="8"
-                [nzErrorTip]="'validation.required' | i18n"
-              >
-                <input
-                  nz-input
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [type]="paramDefine.type"
-                  [id]="paramDefine.field"
-                  [placeholder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                />
-              </nz-form-control>
 
-              <nz-form-label
-                *ngIf="paramDefine.type === 'textarea'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'textarea'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <textarea
-                  nz-input
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                  [placeholder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                  rows="8"
-                ></textarea>
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'password'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'password'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <app-multi-func-input
-                  [placeholder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                  [(value)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                  groupStyle="width: 100%"
-                  type="password"
-                />
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'number'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'number'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <nz-input-number
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [nzMin]="-1000"
-                  [nzMax]="65535"
-                  [nzStep]="1"
-                  [nzPlaceHolder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                ></nz-input-number>
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'boolean'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'boolean'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <nz-switch
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                ></nz-switch>
-              </nz-form-control>
-
-              <nz-form-label *ngIf="paramDefine.type === 'radio'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'radio'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-                <nz-radio-group
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  nzButtonStyle="solid"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                >
-                  <label nz-radio-button [nzValue]="optionItem.value" 
*ngFor="let optionItem of paramDefine.options">
-                    {{ optionItem.label }}
-                  </label>
-                </nz-radio-group>
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'key-value'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'key-value'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <app-key-value-input
-                  [(value)]="advancedParams[i].paramValue"
-                  [id]="paramDefine.field"
-                  keyAlias="Header Name"
-                  valueAlias="Header Value"
-                ></app-key-value-input>
-              </nz-form-control>
-            </nz-form-item>
-          </ng-container>
-        </nz-collapse-panel>
-      </nz-collapse>
-      <ng-template #extraColHeader>
-        <button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" 
nz-tooltip [nzTooltipTitle]="'monitors.advanced.tip' | i18n">
-          <span>{{ 'monitors.advanced' | i18n }}</span>
-          <i nz-icon nzType="down-circle" nzTheme="outline"></i>
-        </button>
-      </ng-template>
-
-      <nz-form-item>
-        <nz-form-label nzSpan="7" nzFor="collector" 
[nzTooltipTitle]="'monitor.collector.tip' | i18n">
-          {{ 'monitor.collector' | i18n }}
-        </nz-form-label>
-        <nz-form-control nzSpan="8">
-          <nz-select
-            [(ngModel)]="collector"
-            [nzDropdownMatchSelectWidth]="false"
-            name="collector"
-            id="collector"
-            [nzCustomTemplate]="collectorTemplate"
-          >
-            <nz-option
-              nzCustomContent
-              [nzValue]="''"
-              [nzLabel]="('monitor.collector.system.default' | i18n) + '-' + 
('collector.mode.public' | i18n)"
-            >
-              <nz-tag nzColor="processing">{{ 
'monitor.collector.system.default' | i18n }}</nz-tag>
-              <nz-tag nzColor="success">{{ 'collector.mode.public' | i18n 
}}</nz-tag>
-            </nz-option>
-            <nz-option nzCustomContent *ngFor="let item of collectors" 
[nzValue]="item.name" [nzLabel]="item.name">
-              <nz-tag [nzColor]="item.status == 0 ? 'processing' : 'error'">{{
-                item.status == 0 ? ('monitor.collector.status.online' | i18n) 
: ('monitor.collector.status.offline' | i18n)
-              }}</nz-tag>
-              <span nz-icon nzType="bug" nzTheme="outline" 
style="margin-right: 8px"></span>
-              <nz-tag nzColor="processing">{{ item.name }}</nz-tag>
-              <nz-tag nzColor="processing">{{ item.ip }}</nz-tag>
-              <nz-tag [nzColor]="item.mode == 'private' ? 'warning' : 
'success'">
-                {{ item.mode == 'private' ? ('collector.mode.private' | i18n) 
: ('collector.mode.public' | i18n) }}
-              </nz-tag>
-            </nz-option>
-          </nz-select>
-          <ng-template #collectorTemplate let-selected>
-            <nz-tag nzColor="processing">{{ selected.nzLabel }}</nz-tag>
-          </ng-template>
-        </nz-form-control>
-      </nz-form-item>
-
-      <nz-form-item>
-        <nz-form-label nzSpan="7" nzFor="intervals" 
[nzTooltipTitle]="'monitor.intervals.tip' | i18n">
-          {{ 'monitor.intervals' | i18n }}
-        </nz-form-label>
-        <nz-form-control nzSpan="8">
-          <nz-input-number
-            [(ngModel)]="monitor.intervals"
-            [nzMin]="monitor.app === 'push' ? 1 : 30"
-            [nzMax]="604800"
-            [nzStep]="monitor.app === 'push' ? 1 : 60"
-            name="intervals"
-            id="intervals"
-          >
-          </nz-input-number>
-          <nz-tag style="margin-left: 6px">{{ 'common.time.unit.second' | i18n 
}}</nz-tag>
-        </nz-form-control>
-      </nz-form-item>
-
-      <nz-form-item>
-        <nz-form-label nzSpan="7" nzFor="tags" 
[nzTooltipTitle]="'tag.bind.tip' | i18n">
-          {{ 'tag.bind' | i18n }}
-        </nz-form-label>
-        <nz-form-control nzSpan="8">
-          <nz-tag
-            *ngFor="let tag of monitor.tags; let i = index"
-            [nzMode]="tag.type === 1 ? 'closeable' : 'default'"
-            (nzOnClose)="onRemoveTag(tag)"
-            [nzColor]="tag.color"
-            style="margin-top: 4px"
-          >
-            {{ sliceTagName(tag) }}
-          </nz-tag>
-          <a (click)="onShowTagsModal()">
-            <nz-tag style="margin-top: 4px">
-              <i nz-icon nzType="plus"></i>
-              {{ 'tag.new' | i18n }}
-            </nz-tag>
-          </a>
-        </nz-form-control>
-      </nz-form-item>
-
-      <nz-form-item>
-        <nz-form-label [nzSpan]="7" nzFor="description" 
[nzTooltipTitle]="'monitor.description.tip' | i18n">
-          {{ 'monitor.description' | i18n }}
-        </nz-form-label>
-        <nz-form-control [nzSpan]="8">
-          <nz-textarea-count [nzMaxCharacterCount]="100">
-            <textarea [(ngModel)]="monitor.description" rows="3" nz-input 
name="description" id="description"></textarea>
-          </nz-textarea-count>
-        </nz-form-control>
-      </nz-form-item>
-
-      <div nz-row>
-        <div nz-col [nzXs]="{ span: 24 }" [nzLg]="{ span: 8, offset: 7 }" 
style="text-align: center">
-          <button
-            nz-button
-            nzType="primary"
-            type="submit"
-            nz-tooltip
-            [nzTooltipTitle]="'monitors.detect.tip' | i18n"
-            (click)="onDetect(editForm.form)"
-          >
-            {{ 'common.button.detect' | i18n }}
-          </button>
-          <button nz-button nzType="primary" type="submit" 
(click)="onSubmit(editForm.form)"> {{ 'common.button.ok' | i18n }} </button>
-          <button nz-button nzType="primary" type="reset" 
(click)="onCancel()"> {{ 'common.button.cancel' | i18n }} </button>
-        </div>
-      </div>
-    </form>
-  </div>
-</nz-spin>
+<nz-divider></nz-divider>
 
-<!-- 选择TAG弹出框 -->
-<nz-modal
-  [(nzVisible)]="isManageModalVisible"
-  [nzTitle]="'tag.bind' | i18n"
-  (nzOnCancel)="onManageModalCancel()"
-  (nzOnOk)="onManageModalOk()"
-  nzMaskClosable="false"
-  nzWidth="30%"
-  [nzOkLoading]="isManageModalOkLoading"
->
-  <div *nzModalContent class="-inner-content">
-    <input
-      style="margin-left: 5px; width: 50%; text-align: center"
-      nz-input
-      type="text"
-      [placeholder]="'tag.search' | i18n"
-      nzSize="default"
-      (keyup.enter)="loadTagsTable()"
-      [(ngModel)]="tagSearch"
-    />
-    <button nz-button nzType="primary" routerLink="/setting/tags" 
style="margin-left: 5px">
-      <i nz-icon nzType="setting" nzTheme="outline"></i>
-      {{ 'tag.setting' | i18n }}
-    </button>
-    <nz-table #smallTable nzSize="small" [nzData]="tags" [nzPageSize]="8" 
[nzLoading]="tagTableLoading">
-      <thead>
-        <tr>
-          <th nzAlign="center" nzLeft nzWidth="4%" 
[(nzChecked)]="tagCheckedAll" (nzCheckedChange)="onAllChecked($event)"></th>
-          <th nzAlign="left">{{ 'tag' | i18n }}</th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr *ngFor="let data of smallTable.data">
-          <td nzAlign="center" nzLeft [nzChecked]="checkedTags.has(data)" 
(nzCheckedChange)="onItemChecked(data, $event)"></td>
-          <td nzAlign="left">
-            <nz-tag *ngIf="data.tagValue == undefined || data.tagValue.trim() 
== ''" [nzColor]="data.color">{{ data.name }}</nz-tag>
-            <nz-tag *ngIf="data.tagValue != undefined && data.tagValue.trim() 
!= ''" [nzColor]="data.color">
-              {{ data.name + ':' + data.tagValue }}
-            </nz-tag>
-          </td>
-        </tr>
-      </tbody>
-    </nz-table>
-  </div>
-</nz-modal>
+<app-monitor-form
+  [loading]="isSpinning"
+  [loadingTip]="spinningTip"
+  [monitor]="monitor"
+  [hostName]="hostName"
+  [params]="params"
+  [paramDefines]="paramDefines"
+  [advancedParams]="advancedParams"
+  [advancedParamDefines]="advancedParamDefines"
+  [collector]="collector"
+  [collectors]="collectors"
+  (formCancel)="onCancel()"
+  (formSubmit)="onSubmit($event)"
+  (formDetect)="onDetect($event)"
+/>
diff --git 
a/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.ts 
b/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.ts
index b33393e43..72ff1bebe 100644
--- a/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.ts
+++ b/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.ts
@@ -24,18 +24,16 @@ import { I18NService } from '@core';
 import { ALAIN_I18N_TOKEN, TitleService } from '@delon/theme';
 import { NzNotificationService } from 'ng-zorro-antd/notification';
 import { throwError } from 'rxjs';
-import { finalize, switchMap } from 'rxjs/operators';
+import { switchMap } from 'rxjs/operators';
 
 import { Collector } from '../../../pojo/Collector';
 import { Message } from '../../../pojo/Message';
 import { Monitor } from '../../../pojo/Monitor';
 import { Param } from '../../../pojo/Param';
 import { ParamDefine } from '../../../pojo/ParamDefine';
-import { Tag } from '../../../pojo/Tag';
 import { AppDefineService } from '../../../service/app-define.service';
 import { CollectorService } from '../../../service/collector.service';
 import { MonitorService } from '../../../service/monitor.service';
-import { TagService } from '../../../service/tag.service';
 
 @Component({
   selector: 'app-monitor-modify',
@@ -50,7 +48,6 @@ export class MonitorEditComponent implements OnInit {
     private router: Router,
     private titleSvc: TitleService,
     private notifySvc: NzNotificationService,
-    private tagSvc: TagService,
     private collectorSvc: CollectorService,
     @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
   ) {}
@@ -64,7 +61,6 @@ export class MonitorEditComponent implements OnInit {
   monitor = new Monitor();
   collectors!: Collector[];
   collector: string = '';
-  profileForm: FormGroup = new FormGroup({});
   detected: boolean = false;
   isSpinning: boolean = false;
   spinningTip: string = 'Loading...';
@@ -203,21 +199,6 @@ export class MonitorEditComponent implements OnInit {
     });
   }
 
-  onParamBooleanChanged(booleanValue: boolean, field: string) {
-    // 对SSL的端口联动处理, 不开启SSL默认80端口,开启SSL默认443
-    if (field === 'ssl') {
-      this.params.forEach(param => {
-        if (param.field === 'port') {
-          if (booleanValue) {
-            param.paramValue = '443';
-          } else {
-            param.paramValue = '80';
-          }
-        }
-      });
-    }
-  }
-
   onDependChanged(dependValue: string, dependField: string) {
     this.paramDefines.forEach((paramDefine, index) => {
       if (paramDefine.depend) {
@@ -243,37 +224,12 @@ export class MonitorEditComponent implements OnInit {
     });
   }
 
-  onSubmit(formGroup: FormGroup) {
-    if (formGroup.invalid) {
-      Object.values(formGroup.controls).forEach(control => {
-        if (control.invalid) {
-          control.markAsDirty();
-          control.updateValueAndValidity({ onlySelf: true });
-        }
-      });
-      return;
-    }
-    this.monitor.host = this.monitor.host.trim();
-    this.monitor.name = this.monitor.name.trim();
-    // todo 暂时单独设置host属性值
-    this.params.forEach(param => {
-      if (param.field === 'host') {
-        param.paramValue = this.monitor.host;
-      }
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
-    this.advancedParams.forEach(param => {
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
+  onSubmit(info: any) {
     let addMonitor = {
       detected: this.detected,
-      monitor: this.monitor,
+      monitor: info.monitor,
       collector: this.collector,
-      params: this.params.concat(this.advancedParams)
+      params: info.params.concat(info.advancedParams)
     };
     if (this.detected) {
       this.spinningTip = this.i18nSvc.fanyi('monitors.spinning-tip.detecting');
@@ -286,7 +242,7 @@ export class MonitorEditComponent implements OnInit {
         this.isSpinning = false;
         if (message.code === 0) {
           this.notifySvc.success(this.i18nSvc.fanyi('monitors.edit.success'), 
'');
-          this.router.navigateByUrl(`/monitors?app=${this.monitor.app}`);
+          this.router.navigateByUrl(`/monitors?app=${info.monitor.app}`);
         } else {
           this.notifySvc.error(this.i18nSvc.fanyi('monitors.edit.failed'), 
message.msg);
         }
@@ -298,37 +254,12 @@ export class MonitorEditComponent implements OnInit {
     );
   }
 
-  onDetect(formGroup: FormGroup) {
-    if (formGroup.invalid) {
-      Object.values(formGroup.controls).forEach(control => {
-        if (control.invalid) {
-          control.markAsDirty();
-          control.updateValueAndValidity({ onlySelf: true });
-        }
-      });
-      return;
-    }
-    this.monitor.host = this.monitor.host.trim();
-    this.monitor.name = this.monitor.name.trim();
-    // todo 暂时单独设置host属性值
-    this.params.forEach(param => {
-      if (param.field === 'host') {
-        param.paramValue = this.monitor.host;
-      }
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
-    this.advancedParams.forEach(param => {
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
+  onDetect(info: any) {
     let detectMonitor = {
       detected: this.detected,
-      monitor: this.monitor,
+      monitor: info.monitor,
       collector: this.collector,
-      params: this.params.concat(this.advancedParams)
+      params: info.params.concat(info.advancedParams)
     };
     this.spinningTip = this.i18nSvc.fanyi('monitors.spinning-tip.detecting');
     this.isSpinning = true;
@@ -353,80 +284,4 @@ export class MonitorEditComponent implements OnInit {
     app = app ? app : '';
     this.router.navigateByUrl(`/monitors?app=${app}`);
   }
-
-  onRemoveTag(tag: Tag) {
-    if (this.monitor != undefined && this.monitor.tags != undefined) {
-      this.monitor.tags = this.monitor.tags.filter(item => item !== tag);
-    }
-  }
-
-  sliceTagName(tag: Tag): string {
-    if (tag.tagValue != undefined && tag.tagValue.trim() != '') {
-      return `${tag.name}:${tag.tagValue}`;
-    } else {
-      return tag.name;
-    }
-  }
-
-  // start Tag model
-  isManageModalVisible = false;
-  isManageModalOkLoading = false;
-  tagCheckedAll: boolean = false;
-  tagTableLoading = false;
-  tagSearch!: string;
-  tags!: Tag[];
-  checkedTags = new Set<Tag>();
-  loadTagsTable() {
-    this.tagTableLoading = true;
-    let tagsReq$ = this.tagSvc.loadTags(this.tagSearch, 1, 0, 1000).subscribe(
-      message => {
-        this.tagTableLoading = false;
-        this.tagCheckedAll = false;
-        this.checkedTags.clear();
-        if (message.code === 0) {
-          let page = message.data;
-          this.tags = page.content;
-        } else {
-          console.warn(message.msg);
-        }
-        tagsReq$.unsubscribe();
-      },
-      error => {
-        this.tagTableLoading = false;
-        tagsReq$.unsubscribe();
-      }
-    );
-  }
-  onShowTagsModal() {
-    this.isManageModalVisible = true;
-    this.loadTagsTable();
-  }
-  onManageModalCancel() {
-    this.isManageModalVisible = false;
-  }
-  onManageModalOk() {
-    this.isManageModalOkLoading = true;
-    this.checkedTags.forEach(item => {
-      if (this.monitor.tags.find(tag => tag.id == item.id) == undefined) {
-        this.monitor.tags.push(item);
-      }
-    });
-    this.isManageModalOkLoading = false;
-    this.isManageModalVisible = false;
-  }
-  onAllChecked(checked: boolean) {
-    if (checked) {
-      this.tags.forEach(tag => this.checkedTags.add(tag));
-    } else {
-      this.checkedTags.clear();
-    }
-  }
-  onItemChecked(tag: Tag, checked: boolean) {
-    if (checked) {
-      this.checkedTags.add(tag);
-    } else {
-      this.checkedTags.delete(tag);
-    }
-  }
-  // end tag model
 }
diff --git 
a/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.html 
b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.html
new file mode 100644
index 000000000..33351b86b
--- /dev/null
+++ b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.html
@@ -0,0 +1,139 @@
+<!--
+  ~ 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.
+-->
+
+<nz-spin [nzSpinning]="loading" [nzTip]="loadingTip" nzSize="large">
+  <div class="-inner-content">
+    <form nz-form #form="ngForm">
+      <app-form-item
+        [item]="{
+          field: 'host',
+          type: 'text',
+          name: hostName ? hostName : ('monitor.host' | i18n),
+          required: true,
+          placeholder: 'monitor.host.tip' | i18n
+        }"
+        [(value)]="monitor.host"
+        (valueChange)="onHostChange($event)"
+      />
+
+      <app-form-item
+        [item]="{
+          field: 'name',
+          type: 'text',
+          name: 'monitor.name' | i18n,
+          required: true,
+          placeholder: 'monitor.name.tip' | i18n
+        }"
+        [(value)]="monitor.name"
+      />
+
+      <ng-container *ngFor="let paramDefine of paramDefines; let i = index">
+        <app-form-item
+          *ngIf="params[i].display && paramDefine.field !== 'host'"
+          [item]="paramDefine"
+          [(value)]="params[i].paramValue"
+          (valueChange)="
+            paramDefine.type === 'boolean'
+              ? onParamBooleanChanged($event, paramDefine.field)
+              : paramDefine.type === 'radio'
+              ? onDependChanged($event, paramDefine.field)
+              : null
+          "
+        />
+      </ng-container>
+
+      <nz-collapse [nzGhost]="true" style="background: ghostwhite; 
margin-bottom: 24px">
+        <ng-template #extraColHeader>
+          <button style="margin-left: 40%" nz-button nzType="dashed" 
nz-tooltip [nzTooltipTitle]="'monitors.advanced.tip' | i18n">
+            <span>{{ 'monitors.advanced' | i18n }}</span>
+            <i nz-icon nzType="down-circle" nzTheme="outline"></i>
+          </button>
+        </ng-template>
+        <nz-collapse-panel [nzHeader]="extraColHeader" [nzShowArrow]="false">
+          <ng-container *ngFor="let paramDefine of advancedParamDefines; let i 
= index">
+            <app-form-item
+              *ngIf="advancedParams[i].display && paramDefine.field !== 'host'"
+              [item]="paramDefine"
+              [(value)]="advancedParams[i].paramValue"
+            />
+          </ng-container>
+        </nz-collapse-panel>
+      </nz-collapse>
+
+      <app-form-item
+        [item]="{
+          field: 'collector',
+          type: 'collectors-selection',
+          name: 'monitor.collector' | i18n,
+          tooltip: 'monitor.collector.tip' | i18n
+        }"
+        [extra]="{collectors}"
+        [(value)]="collector"
+      />
+
+      <app-form-item
+        [item]="{
+          field: 'intervals',
+          type: 'intervals',
+          name: 'monitor.intervals' | i18n,
+          tooltip: 'monitor.intervals.tip' | i18n
+        }"
+        [extra]="{ interval_type: monitor.app }"
+        [(value)]="monitor.intervals"
+      />
+
+      <app-form-item
+        [item]="{
+          field: 'tags',
+          type: 'tags-selection',
+          name: 'tag.bind' | i18n,
+          tooltip: 'tag.bind.tip' | i18n
+        }"
+        [(value)]="monitor.tags"
+      />
+
+      <app-form-item
+        [item]="{
+          field: 'description',
+          type: 'textarea-limit',
+          name: 'monitor.description' | i18n,
+          tooltip: 'monitor.description.tip' | i18n
+        }"
+        [(value)]="monitor.description"
+      />
+
+      <div nz-row>
+        <div nz-col [nzXs]="{ span: 24 }" [nzLg]="{ span: 8, offset: 7 }" 
style="text-align: center">
+          <button
+            nz-button
+            nzType="primary"
+            type="submit"
+            nz-tooltip
+            [nzTooltipTitle]="'monitors.detect.tip' | i18n"
+            (click)="onDetect(form.form)"
+          >
+            {{ 'common.button.detect' | i18n }}
+          </button>
+          <button nz-button nzType="primary" type="submit" 
(click)="onSubmit(form.form)"> {{ 'common.button.ok' | i18n }} </button>
+          <button nz-button nzType="primary" type="reset" 
(click)="onCancel()"> {{ 'common.button.cancel' | i18n }} </button>
+        </div>
+      </div>
+    </form>
+  </div>
+</nz-spin>
diff --git 
a/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.spec.ts 
b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.spec.ts
new file mode 100644
index 000000000..9a3dbd6e2
--- /dev/null
+++ b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.spec.ts
@@ -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.
+ */
+
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MonitorFormComponent } from './monitor-form.component';
+
+describe('MonitorFormComponent', () => {
+  let component: MonitorFormComponent;
+  let fixture: ComponentFixture<MonitorFormComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [MonitorFormComponent]
+    }).compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MonitorFormComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git 
a/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.ts 
b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.ts
new file mode 100644
index 000000000..d28d9fa79
--- /dev/null
+++ b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.ts
@@ -0,0 +1,156 @@
+/*
+ * 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 { Component, EventEmitter, Input, Output } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+
+import { Collector } from '../../../pojo/Collector';
+import { Param } from '../../../pojo/Param';
+import { ParamDefine } from '../../../pojo/ParamDefine';
+
+@Component({
+  selector: 'app-monitor-form',
+  templateUrl: './monitor-form.component.html',
+  styles: []
+})
+export class MonitorFormComponent {
+  @Input() monitor!: any;
+  @Input() loading!: boolean;
+  @Input() loadingTip!: string;
+  @Input() hostName!: string;
+  @Input() collector!: string;
+  @Input() collectors!: Collector[];
+  @Input() params!: Param[];
+  @Input() advancedParams!: Param[];
+  @Input() paramDefines!: ParamDefine[];
+  @Input() advancedParamDefines!: ParamDefine[];
+
+  @Output() readonly formSubmit = new EventEmitter<any>();
+  @Output() readonly formCancel = new EventEmitter<any>();
+  @Output() readonly formDetect = new EventEmitter<any>();
+  @Output() readonly hostChange = new EventEmitter<string>();
+
+  constructor() {}
+
+  onDetect(formGroup: FormGroup) {
+    if (formGroup.invalid) {
+      Object.values(formGroup.controls).forEach(control => {
+        if (control.invalid) {
+          control.markAsDirty();
+          control.updateValueAndValidity({ onlySelf: true });
+        }
+      });
+      return;
+    }
+    this.monitor.host = this.monitor.host.trim();
+    this.monitor.name = this.monitor.name.trim();
+    // todo 暂时单独设置host属性值
+    this.params.forEach(param => {
+      if (param.field === 'host') {
+        param.paramValue = this.monitor.host;
+      }
+      if (param.paramValue != null && typeof param.paramValue == 'string') {
+        param.paramValue = (param.paramValue as string).trim();
+      }
+    });
+    this.advancedParams.forEach(param => {
+      if (param.paramValue != null && typeof param.paramValue == 'string') {
+        param.paramValue = (param.paramValue as string).trim();
+      }
+    });
+    this.formDetect.emit({ monitor: this.monitor, params: this.params, 
advancedParams: this.advancedParams });
+  }
+
+  onSubmit(formGroup: FormGroup) {
+    if (formGroup.invalid) {
+      Object.values(formGroup.controls).forEach(control => {
+        if (control.invalid) {
+          control.markAsDirty();
+          control.updateValueAndValidity({ onlySelf: true });
+        }
+      });
+      return;
+    }
+    this.monitor.host = this.monitor.host.trim();
+    this.monitor.name = this.monitor.name.trim();
+    // todo 暂时单独设置host属性值
+    this.params.forEach(param => {
+      if (param.field === 'host') {
+        param.paramValue = this.monitor.host;
+      }
+      if (param.paramValue != null && typeof param.paramValue == 'string') {
+        param.paramValue = (param.paramValue as string).trim();
+      }
+    });
+    this.advancedParams.forEach(param => {
+      if (param.paramValue != null && typeof param.paramValue == 'string') {
+        param.paramValue = (param.paramValue as string).trim();
+      }
+    });
+    this.formSubmit.emit({ monitor: this.monitor, params: this.params, 
advancedParams: this.advancedParams });
+  }
+
+  onCancel() {
+    this.formCancel.emit();
+  }
+
+  onHostChange(host: string) {
+    this.hostChange.emit(host);
+  }
+
+  onParamBooleanChanged(booleanValue: boolean, field: string) {
+    // 对SSL的端口联动处理, 不开启SSL默认80端口,开启SSL默认443
+    if (field === 'ssl') {
+      this.params.forEach(param => {
+        if (param.field === 'port') {
+          if (booleanValue) {
+            param.paramValue = '443';
+          } else {
+            param.paramValue = '80';
+          }
+        }
+      });
+    }
+  }
+
+  onDependChanged(dependValue: string, dependField: string) {
+    this.paramDefines.forEach((paramDefine, index) => {
+      if (paramDefine.depend) {
+        let fieldValues = new 
Map(Object.entries(paramDefine.depend)).get(dependField);
+        if (fieldValues) {
+          this.params[index].display = false;
+          if (fieldValues.map(String).includes(dependValue)) {
+            this.params[index].display = true;
+          }
+        }
+      }
+    });
+    this.advancedParamDefines.forEach((advancedParamDefine, index) => {
+      if (advancedParamDefine.depend) {
+        let fieldValues = new 
Map(Object.entries(advancedParamDefine.depend)).get(dependField);
+        if (fieldValues) {
+          this.advancedParams[index].display = false;
+          if (fieldValues.map(String).includes(dependValue)) {
+            this.advancedParams[index].display = true;
+          }
+        }
+      }
+    });
+  }
+}
diff --git 
a/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html 
b/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html
index e5779cb8a..6e0c211ce 100644
--- a/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html
+++ b/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html
@@ -23,466 +23,22 @@
   [guild_link]="'monitor.app.' + monitor.app + '.helpLink' | i18n"
   [icon_name]="'plus-circle'"
 ></app-help-message-show>
-<nz-divider></nz-divider>
-
-<nz-spin [nzSpinning]="isSpinning" [nzTip]="spinningTip" nzSize="large">
-  <div class="-inner-content">
-    <form nz-form #newForm="ngForm">
-      <nz-form-item>
-        <nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" 
[nzTooltipTitle]="'monitor.host.tip' | i18n">
-          {{ hostName ? hostName : ('monitor.host' | i18n) }}
-        </nz-form-label>
-        <nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | 
i18n">
-          <input
-            [(ngModel)]="monitor.host"
-            nz-input
-            name="host"
-            type="text"
-            id="host"
-            required
-            [placeholder]="'monitor.host.tip' | i18n"
-            (ngModelChange)="onHostChange($event)"
-          />
-        </nz-form-control>
-      </nz-form-item>
-      <nz-form-item>
-        <nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" 
[nzTooltipTitle]="'monitor.name.tip' | i18n">
-          {{ 'monitor.name' | i18n }}
-        </nz-form-label>
-        <nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | 
i18n">
-          <input [(ngModel)]="monitor.name" nz-input required name="name" 
type="text" id="name" [placeholder]="'monitor.name.tip' | i18n" />
-        </nz-form-control>
-      </nz-form-item>
-
-      <ng-container *ngFor="let paramDefine of paramDefines; let i = index">
-        <nz-form-item *ngIf="params[i].display">
-          <nz-form-label
-            *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-            nzSpan="7"
-            [nzRequired]="paramDefine.required"
-            [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control
-            *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-            nzSpan="8"
-            [nzErrorTip]="'validation.required' | i18n"
-          >
-            <input
-              nz-input
-              [required]="paramDefine.required"
-              [(ngModel)]="params[i].paramValue"
-              [name]="paramDefine.field"
-              [type]="paramDefine.type"
-              [id]="paramDefine.field"
-              [placeholder]="paramDefine.placeholder ? paramDefine.placeholder 
: ''"
-            />
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'textarea'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'textarea'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <textarea
-              nz-input
-              [(ngModel)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-              [placeholder]="paramDefine.placeholder ? paramDefine.placeholder 
: ''"
-              rows="8"
-            ></textarea>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'password'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'password'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <app-multi-func-input
-              [placeholder]="paramDefine.placeholder ? paramDefine.placeholder 
: ''"
-              [(value)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-              groupStyle="width: 100%"
-              type="password"
-            />
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'number'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'number'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <nz-input-number
-              [(ngModel)]="params[i].paramValue"
-              [required]="paramDefine.required"
-              [nzMin]="getNumber(paramDefine.range || '', 0) || -1000"
-              [nzMax]="getNumber(paramDefine.range || '', 1) || 65535"
-              [nzStep]="1"
-              [nzPlaceHolder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-            ></nz-input-number>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'boolean'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'boolean'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <nz-switch
-              [(ngModel)]="params[i].paramValue"
-              (ngModelChange)="onParamBooleanChanged($event, 
paramDefine.field)"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-            ></nz-switch>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'radio'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'radio'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <nz-radio-group
-              [(ngModel)]="params[i].paramValue"
-              nzButtonStyle="solid"
-              (ngModelChange)="onDependChanged($event, paramDefine.field)"
-              [required]="paramDefine.required"
-              [name]="paramDefine.field"
-              [id]="paramDefine.field"
-            >
-              <label nz-radio-button [nzValue]="optionItem.value" *ngFor="let 
optionItem of paramDefine.options">
-                {{ optionItem.label }}
-              </label>
-            </nz-radio-group>
-          </nz-form-control>
-
-          <nz-form-label *ngIf="paramDefine.type === 'key-value'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'key-value'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-            <app-key-value-input
-              [(value)]="params[i].paramValue"
-              [id]="paramDefine.field"
-              [keyAlias]="paramDefine.keyAlias ? paramDefine.keyAlias : 'Name'"
-              [valueAlias]="paramDefine.valueAlias ? paramDefine.valueAlias : 
'Value'"
-            ></app-key-value-input>
-          </nz-form-control>
-
-          <nz-form-label
-            *ngIf="paramDefine.type === 'metrics-field'"
-            nzSpan="7"
-            [nzRequired]="paramDefine.required"
-            [nzFor]="paramDefine.field"
-            >{{ paramDefine.name }}
-          </nz-form-label>
-          <nz-form-control *ngIf="paramDefine.type === 'metrics-field'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-            <app-metrics-field-input
-              [(value)]="params[i].paramValue"
-              [id]="paramDefine.field"
-              [FieldAlias]="'Field'"
-              [UnitAlias]="'Unit'"
-              [TypeAlias]="'Type'"
-            ></app-metrics-field-input>
-          </nz-form-control>
-        </nz-form-item>
-      </ng-container>
-
-      <nz-collapse [nzGhost]="true" style="margin-bottom: 16px">
-        <nz-collapse-panel [nzHeader]="extraColHeader" [nzShowArrow]="false">
-          <ng-container *ngFor="let paramDefine of advancedParamDefines; let i 
= index">
-            <nz-form-item *ngIf="advancedParams[i].display">
-              <nz-form-label
-                *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control
-                *ngIf="paramDefine.field !== 'host' && (paramDefine.type === 
'text' || paramDefine.type === 'array')"
-                nzSpan="8"
-                [nzErrorTip]="'validation.required' | i18n"
-              >
-                <input
-                  nz-input
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [type]="paramDefine.type"
-                  [id]="paramDefine.field"
-                  [placeholder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                />
-              </nz-form-control>
 
-              <nz-form-label
-                *ngIf="paramDefine.type === 'textarea'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'textarea'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <textarea
-                  nz-input
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                  [placeholder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                  rows="8"
-                ></textarea>
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'password'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'password'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <app-multi-func-input
-                  [placeholder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                  [(value)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                  groupStyle="width: 100%"
-                  type="password"
-                />
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'number'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'number'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <nz-input-number
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [nzMin]="-1000"
-                  [nzMax]="65535"
-                  [nzStep]="1"
-                  [nzPlaceHolder]="paramDefine.placeholder ? 
paramDefine.placeholder : ''"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                ></nz-input-number>
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'boolean'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'boolean'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <nz-switch
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                ></nz-switch>
-              </nz-form-control>
-
-              <nz-form-label *ngIf="paramDefine.type === 'radio'" nzSpan="7" 
[nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'radio'" nzSpan="8" 
[nzErrorTip]="'validation.required' | i18n">
-                <nz-radio-group
-                  [(ngModel)]="advancedParams[i].paramValue"
-                  [required]="paramDefine.required"
-                  nzButtonStyle="solid"
-                  [name]="paramDefine.field"
-                  [id]="paramDefine.field"
-                >
-                  <label nz-radio-button [nzValue]="optionItem.value" 
*ngFor="let optionItem of paramDefine.options">
-                    {{ optionItem.label }}
-                  </label>
-                </nz-radio-group>
-              </nz-form-control>
-
-              <nz-form-label
-                *ngIf="paramDefine.type === 'key-value'"
-                nzSpan="7"
-                [nzRequired]="paramDefine.required"
-                [nzFor]="paramDefine.field"
-                >{{ paramDefine.name }}
-              </nz-form-label>
-              <nz-form-control *ngIf="paramDefine.type === 'key-value'" 
nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
-                <app-key-value-input
-                  [(value)]="advancedParams[i].paramValue"
-                  [id]="paramDefine.field"
-                  keyAlias="Header Name"
-                  valueAlias="Header Value"
-                ></app-key-value-input>
-              </nz-form-control>
-            </nz-form-item>
-          </ng-container>
-        </nz-collapse-panel>
-      </nz-collapse>
-      <ng-template #extraColHeader>
-        <button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" 
nz-tooltip [nzTooltipTitle]="'monitors.advanced.tip' | i18n">
-          <span>{{ 'monitors.advanced' | i18n }}</span>
-          <i nz-icon nzType="down-circle" nzTheme="outline"></i>
-        </button>
-      </ng-template>
-
-      <nz-form-item>
-        <nz-form-label nzSpan="7" nzFor="collector" 
[nzTooltipTitle]="'monitor.collector.tip' | i18n">
-          {{ 'monitor.collector' | i18n }}
-        </nz-form-label>
-        <nz-form-control nzSpan="8">
-          <nz-select
-            [(ngModel)]="collector"
-            [nzDropdownMatchSelectWidth]="false"
-            name="collector"
-            id="collector"
-            [nzCustomTemplate]="collectorTemplate"
-          >
-            <nz-option
-              nzCustomContent
-              [nzValue]="''"
-              [nzLabel]="('monitor.collector.system.default' | i18n) + '-' + 
('collector.mode.public' | i18n)"
-            >
-              <nz-tag nzColor="processing">{{ 
'monitor.collector.system.default' | i18n }}</nz-tag>
-              <nz-tag nzColor="success">{{ 'collector.mode.public' | i18n 
}}</nz-tag>
-            </nz-option>
-            <nz-option nzCustomContent *ngFor="let item of collectors" 
[nzValue]="item.name" [nzLabel]="item.name">
-              <nz-tag [nzColor]="item.status == 0 ? 'processing' : 'error'">{{
-                item.status == 0 ? ('monitor.collector.status.online' | i18n) 
: ('monitor.collector.status.offline' | i18n)
-              }}</nz-tag>
-              <span nz-icon nzType="bug" nzTheme="outline" 
style="margin-right: 8px"></span>
-              <nz-tag nzColor="processing">{{ item.name }}</nz-tag>
-              <nz-tag nzColor="processing">{{ item.ip }}</nz-tag>
-              <nz-tag [nzColor]="item.mode == 'private' ? 'warning' : 
'success'">
-                {{ item.mode == 'private' ? ('collector.mode.private' | i18n) 
: ('collector.mode.public' | i18n) }}
-              </nz-tag>
-            </nz-option>
-          </nz-select>
-          <ng-template #collectorTemplate let-selected>
-            <nz-tag nzColor="processing">{{ selected.nzLabel }}</nz-tag>
-          </ng-template>
-        </nz-form-control>
-      </nz-form-item>
-
-      <nz-form-item>
-        <nz-form-label nzSpan="7" nzFor="intervals" 
[nzTooltipTitle]="'monitor.intervals.tip' | i18n">
-          {{ 'monitor.intervals' | i18n }}
-        </nz-form-label>
-        <nz-form-control nzSpan="8">
-          <nz-input-number
-            [(ngModel)]="monitor.intervals"
-            [nzMin]="monitor.app === 'push' ? 1 : 30"
-            [nzMax]="604800"
-            [nzStep]="monitor.app === 'push' ? 1 : 60"
-            name="intervals"
-            id="intervals"
-          >
-          </nz-input-number>
-          <nz-tag style="margin-left: 6px">{{ 'common.time.unit.second' | i18n 
}}</nz-tag>
-        </nz-form-control>
-      </nz-form-item>
-
-      <nz-form-item>
-        <nz-form-label nzSpan="7" nzFor="tags" 
[nzTooltipTitle]="'tag.bind.tip' | i18n">
-          {{ 'tag.bind' | i18n }}
-        </nz-form-label>
-        <nz-form-control nzSpan="8">
-          <nz-tag
-            *ngFor="let tag of monitor.tags; let i = index"
-            [nzMode]="tag.type === 1 ? 'closeable' : 'default'"
-            (nzOnClose)="onRemoveTag(tag)"
-            [nzColor]="tag.color"
-            style="margin-top: 4px"
-          >
-            {{ sliceTagName(tag) }}
-          </nz-tag>
-          <a (click)="onShowTagsModal()">
-            <nz-tag style="margin-top: 4px">
-              <i nz-icon nzType="plus"></i>
-              {{ 'tag.new' | i18n }}
-            </nz-tag>
-          </a>
-        </nz-form-control>
-      </nz-form-item>
-
-      <nz-form-item>
-        <nz-form-label [nzSpan]="7" nzFor="description" 
[nzTooltipTitle]="'monitor.description.tip' | i18n">
-          {{ 'monitor.description' | i18n }}
-        </nz-form-label>
-        <nz-form-control [nzSpan]="8">
-          <nz-textarea-count [nzMaxCharacterCount]="100">
-            <textarea [(ngModel)]="monitor.description" rows="3" nz-input 
name="description" id="description"></textarea>
-          </nz-textarea-count>
-        </nz-form-control>
-      </nz-form-item>
-
-      <div nz-row>
-        <div nz-col [nzXs]="{ span: 24 }" [nzLg]="{ span: 8, offset: 7 }" 
style="text-align: center">
-          <button
-            nz-button
-            nzType="primary"
-            type="submit"
-            nz-tooltip
-            [nzTooltipTitle]="'monitors.detect.tip' | i18n"
-            (click)="onDetect(newForm.form)"
-          >
-            {{ 'common.button.detect' | i18n }}
-          </button>
-          <button nz-button nzType="primary" type="submit" 
(click)="onSubmit(newForm.form)"> {{ 'common.button.ok' | i18n }} </button>
-          <button nz-button nzType="primary" type="reset" 
(click)="onCancel()"> {{ 'common.button.cancel' | i18n }} </button>
-        </div>
-      </div>
-    </form>
-  </div>
-</nz-spin>
+<nz-divider></nz-divider>
 
-<!-- 选择TAG弹出框 -->
-<nz-modal
-  [(nzVisible)]="isManageModalVisible"
-  [nzTitle]="'tag.bind' | i18n"
-  (nzOnCancel)="onManageModalCancel()"
-  (nzOnOk)="onManageModalOk()"
-  nzMaskClosable="false"
-  nzWidth="30%"
-  [nzOkLoading]="isManageModalOkLoading"
->
-  <div *nzModalContent class="-inner-content">
-    <input
-      style="margin-left: 5px; width: 50%; text-align: center"
-      nz-input
-      type="text"
-      [placeholder]="'tag.search' | i18n"
-      nzSize="default"
-      (keyup.enter)="loadTagsTable()"
-      [(ngModel)]="tagSearch"
-    />
-    <button nz-button nzType="primary" routerLink="/setting/tags" 
style="margin-left: 5px">
-      <i nz-icon nzType="setting" nzTheme="outline"></i>
-      {{ 'tag.setting' | i18n }}
-    </button>
-    <nz-table #smallTable nzSize="small" [nzData]="tags" [nzPageSize]="8" 
[nzLoading]="tagTableLoading">
-      <thead>
-        <tr>
-          <th nzAlign="center" nzLeft nzWidth="4%" 
[(nzChecked)]="tagCheckedAll" (nzCheckedChange)="onAllChecked($event)"></th>
-          <th nzAlign="left">{{ 'tag' | i18n }}</th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr *ngFor="let data of smallTable.data">
-          <td nzAlign="center" nzLeft [nzChecked]="checkedTags.has(data)" 
(nzCheckedChange)="onItemChecked(data, $event)"></td>
-          <td nzAlign="left">
-            <nz-tag *ngIf="data.tagValue == undefined || data.tagValue.trim() 
== ''" [nzColor]="data.color">{{ data.name }}</nz-tag>
-            <nz-tag *ngIf="data.tagValue != undefined && data.tagValue.trim() 
!= ''" [nzColor]="data.color">
-              {{ data.name + ':' + data.tagValue }}
-            </nz-tag>
-          </td>
-        </tr>
-      </tbody>
-    </nz-table>
-  </div>
-</nz-modal>
+<app-monitor-form
+  [loading]="isSpinning"
+  [loadingTip]="spinningTip"
+  [monitor]="monitor"
+  [hostName]="hostName"
+  [params]="params"
+  [paramDefines]="paramDefines"
+  [advancedParams]="advancedParams"
+  [advancedParamDefines]="advancedParamDefines"
+  [collector]="collector"
+  [collectors]="collectors"
+  (hostChange)="onHostChange($event)"
+  (formCancel)="onCancel()"
+  (formSubmit)="onSubmit($event)"
+  (formDetect)="onDetect($event)"
+/>
diff --git 
a/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.ts 
b/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.ts
index 0f439adb9..3b3ff37b9 100644
--- a/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.ts
+++ b/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.ts
@@ -17,12 +17,11 @@
  * under the License.
  */
 
-import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
-import { FormBuilder, FormGroup } from '@angular/forms';
+import { Component, Inject, OnInit } from '@angular/core';
+import { FormGroup } from '@angular/forms';
 import { ActivatedRoute, ParamMap, Router } from '@angular/router';
 import { I18NService } from '@core';
 import { ALAIN_I18N_TOKEN, TitleService } from '@delon/theme';
-import { List } from 'echarts';
 import { NzNotificationService } from 'ng-zorro-antd/notification';
 import { switchMap } from 'rxjs/operators';
 
@@ -31,11 +30,9 @@ import { Message } from '../../../pojo/Message';
 import { Monitor } from '../../../pojo/Monitor';
 import { Param } from '../../../pojo/Param';
 import { ParamDefine } from '../../../pojo/ParamDefine';
-import { Tag } from '../../../pojo/Tag';
 import { AppDefineService } from '../../../service/app-define.service';
 import { CollectorService } from '../../../service/collector.service';
 import { MonitorService } from '../../../service/monitor.service';
-import { TagService } from '../../../service/tag.service';
 
 @Component({
   selector: 'app-monitor-add',
@@ -61,12 +58,9 @@ export class MonitorNewComponent implements OnInit {
     private route: ActivatedRoute,
     private router: Router,
     private notifySvc: NzNotificationService,
-    private cdr: ChangeDetectorRef,
     @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
     private titleSvc: TitleService,
-    private tagSvc: TagService,
-    private collectorSvc: CollectorService,
-    private formBuilder: FormBuilder
+    private collectorSvc: CollectorService
   ) {
     this.monitor = new Monitor();
     this.monitor.tags = [];
@@ -163,77 +157,12 @@ export class MonitorNewComponent implements OnInit {
     }
   }
 
-  onParamBooleanChanged(booleanValue: boolean, field: string) {
-    // 对SSL的端口联动处理, 不开启SSL默认80端口,开启SSL默认443
-    if (field === 'ssl') {
-      this.params.forEach(param => {
-        if (param.field === 'port') {
-          if (booleanValue) {
-            param.paramValue = '443';
-          } else {
-            param.paramValue = '80';
-          }
-        }
-      });
-    }
-  }
-
-  onDependChanged(dependValue: string, dependField: string) {
-    this.paramDefines.forEach((paramDefine, index) => {
-      if (paramDefine.depend) {
-        let fieldValues = new 
Map(Object.entries(paramDefine.depend)).get(dependField);
-        if (fieldValues) {
-          this.params[index].display = false;
-          if (fieldValues.map(String).includes(dependValue)) {
-            this.params[index].display = true;
-          }
-        }
-      }
-    });
-    this.advancedParamDefines.forEach((advancedParamDefine, index) => {
-      if (advancedParamDefine.depend) {
-        let fieldValues = new 
Map(Object.entries(advancedParamDefine.depend)).get(dependField);
-        if (fieldValues) {
-          this.advancedParams[index].display = false;
-          if (fieldValues.map(String).includes(dependValue)) {
-            this.advancedParams[index].display = true;
-          }
-        }
-      }
-    });
-  }
-
-  onSubmit(formGroup: FormGroup) {
-    if (formGroup.invalid) {
-      Object.values(formGroup.controls).forEach(control => {
-        if (control.invalid) {
-          control.markAsDirty();
-          control.updateValueAndValidity({ onlySelf: true });
-        }
-      });
-      return;
-    }
-    this.monitor.host = this.monitor.host.trim();
-    this.monitor.name = this.monitor.name.trim();
-    // todo 暂时单独设置host属性值
-    this.params.forEach(param => {
-      if (param.field === 'host') {
-        param.paramValue = this.monitor.host;
-      }
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
-    this.advancedParams.forEach(param => {
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
+  onSubmit(info: any) {
     let addMonitor = {
       detected: this.detected,
+      monitor: info.monitor,
       collector: this.collector,
-      monitor: this.monitor,
-      params: this.params.concat(this.advancedParams)
+      params: info.params.concat(info.advancedParams)
     };
     if (this.detected) {
       this.spinningTip = this.i18nSvc.fanyi('monitors.spinning-tip.detecting');
@@ -246,7 +175,7 @@ export class MonitorNewComponent implements OnInit {
         this.isSpinning = false;
         if (message.code === 0) {
           this.notifySvc.success(this.i18nSvc.fanyi('monitors.new.success'), 
'');
-          this.router.navigateByUrl(`/monitors?app=${this.monitor.app}`);
+          this.router.navigateByUrl(`/monitors?app=${info.monitor.app}`);
         } else {
           this.notifySvc.error(this.i18nSvc.fanyi('monitors.new.failed'), 
message.msg);
         }
@@ -258,37 +187,12 @@ export class MonitorNewComponent implements OnInit {
     );
   }
 
-  onDetect(formGroup: FormGroup) {
-    if (formGroup.invalid) {
-      Object.values(formGroup.controls).forEach(control => {
-        if (control.invalid) {
-          control.markAsDirty();
-          control.updateValueAndValidity({ onlySelf: true });
-        }
-      });
-      return;
-    }
-    this.monitor.host = this.monitor.host.trim();
-    this.monitor.name = this.monitor.name.trim();
-    // todo 暂时单独设置host属性值
-    this.params.forEach(param => {
-      if (param.field === 'host') {
-        param.paramValue = this.monitor.host;
-      }
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
-    this.advancedParams.forEach(param => {
-      if (param.paramValue != null && typeof param.paramValue == 'string') {
-        param.paramValue = (param.paramValue as string).trim();
-      }
-    });
+  onDetect(info: any) {
     let detectMonitor = {
       detected: true,
+      monitor: info.monitor,
       collector: this.collector,
-      monitor: this.monitor,
-      params: this.params.concat(this.advancedParams)
+      params: info.params.concat(info.advancedParams)
     };
     this.spinningTip = this.i18nSvc.fanyi('monitors.spinning-tip.detecting');
     this.isSpinning = true;
@@ -313,88 +217,4 @@ export class MonitorNewComponent implements OnInit {
     app = app ? app : '';
     this.router.navigateByUrl(`/monitors?app=${app}`);
   }
-
-  onRemoveTag(tag: Tag) {
-    if (this.monitor != undefined && this.monitor.tags != undefined) {
-      this.monitor.tags = this.monitor.tags.filter(item => item !== tag);
-    }
-  }
-
-  sliceTagName(tag: Tag): string {
-    if (tag.tagValue != undefined && tag.tagValue.trim() != '') {
-      return `${tag.name}:${tag.tagValue}`;
-    } else {
-      return tag.name;
-    }
-  }
-
-  // start Tag model
-  isManageModalVisible = false;
-  isManageModalOkLoading = false;
-  tagCheckedAll: boolean = false;
-  tagTableLoading = false;
-  tagSearch!: string;
-  tags!: Tag[];
-  checkedTags = new Set<Tag>();
-  loadTagsTable() {
-    this.tagTableLoading = true;
-    let tagsReq$ = this.tagSvc.loadTags(this.tagSearch, 1, 0, 1000).subscribe(
-      message => {
-        this.tagTableLoading = false;
-        this.tagCheckedAll = false;
-        this.checkedTags.clear();
-        if (message.code === 0) {
-          let page = message.data;
-          this.tags = page.content;
-        } else {
-          console.warn(message.msg);
-        }
-        tagsReq$.unsubscribe();
-      },
-      error => {
-        this.tagTableLoading = false;
-        tagsReq$.unsubscribe();
-      }
-    );
-  }
-  onShowTagsModal() {
-    this.isManageModalVisible = true;
-    this.loadTagsTable();
-  }
-  onManageModalCancel() {
-    this.isManageModalVisible = false;
-  }
-  onManageModalOk() {
-    this.isManageModalOkLoading = true;
-    this.checkedTags.forEach(item => {
-      if (this.monitor.tags.find(tag => tag.id == item.id) == undefined) {
-        this.monitor.tags.push(item);
-      }
-    });
-    this.isManageModalOkLoading = false;
-    this.isManageModalVisible = false;
-  }
-  onAllChecked(checked: boolean) {
-    if (checked) {
-      this.tags.forEach(tag => this.checkedTags.add(tag));
-    } else {
-      this.checkedTags.clear();
-    }
-  }
-  onItemChecked(tag: Tag, checked: boolean) {
-    if (checked) {
-      this.checkedTags.add(tag);
-    } else {
-      this.checkedTags.delete(tag);
-    }
-  }
-
-  getNumber(rangeString: string, index: number): number | undefined {
-    if (rangeString == undefined || rangeString == '' || rangeString.length <= 
index) {
-      return undefined;
-    }
-    const rangeArray = JSON.parse(rangeString);
-    return rangeArray[index];
-  }
-  // end tag model
 }
diff --git a/web-app/src/app/routes/monitor/monitor.module.ts 
b/web-app/src/app/routes/monitor/monitor.module.ts
index af3794bad..abef9b4cf 100644
--- a/web-app/src/app/routes/monitor/monitor.module.ts
+++ b/web-app/src/app/routes/monitor/monitor.module.ts
@@ -36,6 +36,7 @@ import { MonitorDataChartComponent } from 
'./monitor-data-chart/monitor-data-cha
 import { MonitorDataTableComponent } from 
'./monitor-data-table/monitor-data-table.component';
 import { MonitorDetailComponent } from 
'./monitor-detail/monitor-detail.component';
 import { MonitorEditComponent } from './monitor-edit/monitor-edit.component';
+import { MonitorFormComponent } from './monitor-form/monitor-form.component';
 import { MonitorListComponent } from './monitor-list/monitor-list.component';
 import { MonitorNewComponent } from './monitor-new/monitor-new.component';
 import { MonitorRoutingModule } from './monitor-routing.module';
@@ -43,6 +44,7 @@ import { MonitorRoutingModule } from 
'./monitor-routing.module';
 const COMPONENTS: Array<Type<void>> = [
   MonitorNewComponent,
   MonitorEditComponent,
+  MonitorFormComponent,
   MonitorListComponent,
   MonitorDetailComponent,
   MonitorDataTableComponent,
diff --git 
a/web-app/src/app/shared/components/form-item/form-item.component.html 
b/web-app/src/app/shared/components/form-item/form-item.component.html
new file mode 100644
index 000000000..3865f54a4
--- /dev/null
+++ b/web-app/src/app/shared/components/form-item/form-item.component.html
@@ -0,0 +1,288 @@
+<!--
+  ~ 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.
+-->
+
+<nz-form-item *ngIf="item.type === 'text' || item.type === 'array'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <input
+      nz-input
+      [(ngModel)]="value"
+      (ngModelChange)="onChange($event)"
+      [required]="item.required"
+      [name]="item.field"
+      [type]="item.type"
+      [id]="item.field"
+      [placeholder]="item.placeholder ? item.placeholder : ''"
+    />
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'textarea'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <textarea
+      nz-input
+      [(ngModel)]="value"
+      (ngModelChange)="onChange($event)"
+      [required]="item.required"
+      [name]="item.field"
+      [id]="item.field"
+      [placeholder]="item.placeholder ? item.placeholder : ''"
+      rows="8"
+    ></textarea>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'password'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <app-multi-func-input
+      [placeholder]="item.placeholder ? item.placeholder : ''"
+      [(value)]="value"
+      (valueChange)="onChange($event)"
+      [required]="item.required"
+      [name]="item.field"
+      [id]="item.field"
+      groupStyle="width: 100%"
+      type="password"
+    />
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'number'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <nz-input-number
+      [(ngModel)]="value"
+      (ngModelChange)="onChange($event)"
+      [required]="item.required"
+      [nzMin]="-1000"
+      [nzMax]="65535"
+      [nzStep]="1"
+      [nzPlaceHolder]="item.placeholder ? item.placeholder : ''"
+      [name]="item.field"
+      [id]="item.field"
+    ></nz-input-number>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'boolean'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <nz-switch
+      [(ngModel)]="value"
+      (ngModelChange)="onChange($event)"
+      [required]="item.required"
+      [name]="item.field"
+      [id]="item.field"
+    ></nz-switch>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'radio'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <nz-radio-group
+      [(ngModel)]="value"
+      (ngModelChange)="onChange($event)"
+      [required]="item.required"
+      nzButtonStyle="solid"
+      [name]="item.field"
+      [id]="item.field"
+    >
+      <label nz-radio-button [nzValue]="optionItem.value" *ngFor="let 
optionItem of item.options">
+        {{ optionItem.label }}
+      </label>
+    </nz-radio-group>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'key-value'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <app-key-value-input
+      [(value)]="value"
+      (valueChange)="onChange($event)"
+      [id]="item.field"
+      keyAlias="Header Name"
+      valueAlias="Header Value"
+    ></app-key-value-input>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'metrics-field'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" 
[nzFor]="item.field">{{ item.name }} </nz-form-label>
+  <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
+    <app-metrics-field-input
+      [(value)]="value"
+      (valueChange)="onChange($event)"
+      [id]="item.field"
+      [FieldAlias]="'Field'"
+      [UnitAlias]="'Unit'"
+      [TypeAlias]="'Type'"
+    ></app-metrics-field-input>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'collectors-selection'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" [nzFor]="item.field" 
[nzTooltipTitle]="item.tooltip"
+    >{{ item.name }}
+  </nz-form-label>
+  <nz-form-control nzSpan="8">
+    <nz-select
+      [(ngModel)]="value"
+      (ngModelChange)="onChange($event)"
+      [nzDropdownMatchSelectWidth]="false"
+      name="collector"
+      id="collector"
+      [nzCustomTemplate]="collectorTemplate"
+    >
+      <nz-option
+        nzCustomContent
+        [nzValue]="''"
+        [nzLabel]="('monitor.collector.system.default' | i18n) + '-' + 
('collector.mode.public' | i18n)"
+      >
+        <nz-tag nzColor="processing">{{ 'monitor.collector.system.default' | 
i18n }}</nz-tag>
+        <nz-tag nzColor="success">{{ 'collector.mode.public' | i18n }}</nz-tag>
+      </nz-option>
+      <nz-option nzCustomContent *ngFor="let item of extra.collectors" 
[nzValue]="item.name" [nzLabel]="item.name">
+        <nz-tag [nzColor]="item.status == 0 ? 'processing' : 'error'">{{
+          item.status == 0 ? ('monitor.collector.status.online' | i18n) : 
('monitor.collector.status.offline' | i18n)
+        }}</nz-tag>
+        <span nz-icon nzType="bug" nzTheme="outline" style="margin-right: 
8px"></span>
+        <nz-tag nzColor="processing">{{ item.name }}</nz-tag>
+        <nz-tag nzColor="processing">{{ item.ip }}</nz-tag>
+        <nz-tag [nzColor]="item.mode == 'private' ? 'warning' : 'success'">
+          {{ item.mode == 'private' ? ('collector.mode.private' | i18n) : 
('collector.mode.public' | i18n) }}
+        </nz-tag>
+      </nz-option>
+    </nz-select>
+    <ng-template #collectorTemplate let-selected>
+      <nz-tag nzColor="processing">{{ selected.nzLabel }}</nz-tag>
+    </ng-template>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'intervals'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" [nzFor]="item.field" 
[nzTooltipTitle]="item.tooltip"
+    >{{ item.name }}
+  </nz-form-label>
+  <nz-form-control nzSpan="8">
+    <nz-input-number
+      [(ngModel)]="value"
+      (ngModelChange)="onChange($event)"
+      [nzMin]="extra.interval_type === 'push' ? 1 : 30"
+      [nzMax]="604800"
+      [nzStep]="extra.interval_type === 'push' ? 1 : 60"
+      name="intervals"
+      id="intervals"
+    >
+    </nz-input-number>
+    <nz-tag style="margin-left: 6px">{{ 'common.time.unit.second' | i18n 
}}</nz-tag>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'tags-selection'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" [nzFor]="item.field" 
[nzTooltipTitle]="item.tooltip"
+    >{{ item.name }}
+  </nz-form-label>
+  <nz-form-control nzSpan="8">
+    <nz-tag
+      *ngFor="let tag of value; let i = index"
+      [nzMode]="tag.type === 1 ? 'closeable' : 'default'"
+      (nzOnClose)="onRemoveTag(tag)"
+      [nzColor]="tag.color"
+      style="margin-top: 4px"
+    >
+      {{ sliceTagName(tag) }}
+    </nz-tag>
+    <a (click)="onShowTagsModal()">
+      <nz-tag style="margin-top: 4px">
+        <i nz-icon nzType="plus"></i>
+        {{ 'tag.new' | i18n }}
+      </nz-tag>
+    </a>
+  </nz-form-control>
+</nz-form-item>
+
+<nz-form-item *ngIf="item.type === 'textarea-limit'">
+  <nz-form-label nzSpan="7" [nzRequired]="item.required" [nzFor]="item.field" 
[nzTooltipTitle]="item.tooltip"
+    >{{ item.name }}
+  </nz-form-label>
+  <nz-form-control [nzSpan]="8">
+    <nz-textarea-count [nzMaxCharacterCount]="extra.textarea_limit || 100">
+      <textarea
+        [(ngModel)]="value"
+        (ngModelChange)="onChange($event)"
+        rows="3"
+        nz-input
+        [name]="item.field"
+        [id]="item.field"
+        [placeholder]="item.placeholder ? item.placeholder : ''"
+      ></textarea>
+    </nz-textarea-count>
+  </nz-form-control>
+</nz-form-item>
+
+<!-- 选择TAG弹出框 -->
+<nz-modal
+  *ngIf="item.type === 'tags-selection'"
+  [(nzVisible)]="isManageModalVisible"
+  [nzTitle]="'tag.bind' | i18n"
+  (nzOnCancel)="onManageModalCancel()"
+  (nzOnOk)="onManageModalOk()"
+  nzMaskClosable="false"
+  nzWidth="30%"
+  [nzOkLoading]="isManageModalOkLoading"
+>
+  <div *nzModalContent class="-inner-content">
+    <input
+      style="margin-left: 5px; width: 50%; text-align: center"
+      nz-input
+      type="text"
+      [placeholder]="'tag.search' | i18n"
+      nzSize="default"
+      (keyup.enter)="loadTagsTable()"
+      [(ngModel)]="tagSearch"
+    />
+    <button nz-button nzType="primary" routerLink="/setting/tags" 
style="margin-left: 5px">
+      <i nz-icon nzType="setting" nzTheme="outline"></i>
+      {{ 'tag.setting' | i18n }}
+    </button>
+    <nz-table #smallTable nzSize="small" [nzData]="tags" [nzPageSize]="8" 
[nzLoading]="tagTableLoading">
+      <thead>
+        <tr>
+          <th nzAlign="center" nzLeft nzWidth="4%" 
[(nzChecked)]="tagCheckedAll" (nzCheckedChange)="onAllChecked($event)"></th>
+          <th nzAlign="left">{{ 'tag' | i18n }}</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr *ngFor="let data of smallTable.data">
+          <td nzAlign="center" nzLeft [nzChecked]="checkedTags.has(data)" 
(nzCheckedChange)="onItemChecked(data, $event)"></td>
+          <td nzAlign="left">
+            <nz-tag *ngIf="data.tagValue == undefined || data.tagValue.trim() 
== ''" [nzColor]="data.color">{{ data.name }}</nz-tag>
+            <nz-tag *ngIf="data.tagValue != undefined && data.tagValue.trim() 
!= ''" [nzColor]="data.color">
+              {{ data.name + ':' + data.tagValue }}
+            </nz-tag>
+          </td>
+        </tr>
+      </tbody>
+    </nz-table>
+  </div>
+</nz-modal>
diff --git 
a/web-app/src/app/shared/components/form-item/form-item.component.less 
b/web-app/src/app/shared/components/form-item/form-item.component.less
new file mode 100644
index 000000000..e69de29bb
diff --git 
a/web-app/src/app/shared/components/form-item/form-item.component.spec.ts 
b/web-app/src/app/shared/components/form-item/form-item.component.spec.ts
new file mode 100644
index 000000000..581e39d34
--- /dev/null
+++ b/web-app/src/app/shared/components/form-item/form-item.component.spec.ts
@@ -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.
+ */
+
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FormItemComponent } from './form-item.component';
+
+describe('FormItemComponent', () => {
+  let component: FormItemComponent;
+  let fixture: ComponentFixture<FormItemComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [FormItemComponent]
+    }).compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(FormItemComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web-app/src/app/shared/components/form-item/form-item.component.ts 
b/web-app/src/app/shared/components/form-item/form-item.component.ts
new file mode 100644
index 000000000..18fbe33e8
--- /dev/null
+++ b/web-app/src/app/shared/components/form-item/form-item.component.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 { Component, EventEmitter, Input, Output } from '@angular/core';
+
+import { TagItem } from '../../../pojo/NoticeRule';
+import { Tag } from '../../../pojo/Tag';
+import { TagService } from '../../../service/tag.service';
+
+@Component({
+  selector: 'app-form-item',
+  templateUrl: './form-item.component.html',
+  styleUrls: ['./form-item.component.less']
+})
+export class FormItemComponent {
+  constructor(private tagSvc: TagService) {}
+  @Input() item!: any;
+  @Input() value!: any;
+  @Input() extra: any = {};
+  @Output() readonly valueChange = new EventEmitter<any>();
+
+  isManageModalVisible = false;
+  isManageModalOkLoading = false;
+  checkedTags = new Set<Tag>();
+  tagTableLoading = false;
+  tagCheckedAll: boolean = false;
+  tagSearch!: string;
+  tags!: Tag[];
+
+  loadTagsTable() {
+    this.tagTableLoading = true;
+    let tagsReq$ = this.tagSvc.loadTags(this.tagSearch, 1, 0, 1000).subscribe(
+      message => {
+        this.tagTableLoading = false;
+        this.tagCheckedAll = false;
+        this.checkedTags.clear();
+        if (message.code === 0) {
+          let page = message.data;
+          this.tags = page.content;
+        } else {
+          console.warn(message.msg);
+        }
+        tagsReq$.unsubscribe();
+      },
+      error => {
+        this.tagTableLoading = false;
+        tagsReq$.unsubscribe();
+      }
+    );
+  }
+
+  onChange(value: any) {
+    this.valueChange.emit(value);
+  }
+
+  onRemoveTag(tag: TagItem) {
+    if (this.value != undefined) {
+      this.onChange(this.value.filter((item: TagItem) => item !== tag));
+    }
+  }
+
+  sliceTagName(tag: any): string {
+    if (tag.value != undefined && tag.value.trim() != '') {
+      return `${tag.name}:${tag.value}`;
+    } else {
+      return tag.name;
+    }
+  }
+
+  onShowTagsModal() {
+    this.isManageModalVisible = true;
+    this.loadTagsTable();
+  }
+
+  onManageModalCancel() {
+    this.isManageModalVisible = false;
+  }
+
+  onManageModalOk() {
+    this.isManageModalOkLoading = true;
+    let value = this.value == undefined ? [] : this.value;
+    this.checkedTags.forEach(item => {
+      if (this.value.find((tag: { id: number }) => tag.id == item.id) == 
undefined) {
+        value.push(item);
+      }
+    });
+    this.onChange(value);
+    this.isManageModalOkLoading = false;
+    this.isManageModalVisible = false;
+  }
+
+  onAllChecked(checked: boolean) {
+    if (checked) {
+      this.tags.forEach(tag => this.checkedTags.add(tag));
+    } else {
+      this.checkedTags.clear();
+    }
+  }
+
+  onItemChecked(tag: Tag, checked: boolean) {
+    if (checked) {
+      this.checkedTags.add(tag);
+    } else {
+      this.checkedTags.delete(tag);
+    }
+  }
+}
diff --git a/web-app/src/app/shared/shared.module.ts 
b/web-app/src/app/shared/shared.module.ts
index 4f73806be..4091bc6b4 100644
--- a/web-app/src/app/shared/shared.module.ts
+++ b/web-app/src/app/shared/shared.module.ts
@@ -7,8 +7,11 @@ import { DelonFormModule } from '@delon/form';
 import { AlainThemeModule } from '@delon/theme';
 import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
 import { NzDividerComponent } from 'ng-zorro-antd/divider';
+import { NzRadioComponent, NzRadioGroupComponent } from 'ng-zorro-antd/radio';
+import { NzSwitchComponent } from 'ng-zorro-antd/switch';
 import { NzTagModule } from 'ng-zorro-antd/tag';
 
+import { FormItemComponent } from './components/form-item/form-item.component';
 import { HelpMessageShowComponent } from 
'./components/help-message-show/help-message-show.component';
 import { KeyValueInputComponent } from 
'./components/key-value-input/key-value-input.component';
 import { MetricsFieldInputComponent } from 
'./components/metrics-field-input/metrics-field-input.component';
@@ -28,6 +31,7 @@ const COMPONENTS: Array<Type<void>> = [
   HelpMessageShowComponent,
   MetricsFieldInputComponent,
   ToolbarComponent,
+  FormItemComponent,
   MonitorSelectMenuComponent
 ];
 const DIRECTIVES: Array<Type<void>> = [TimezonePipe, I18nElsePipe, 
ElapsedTimePipe];
@@ -46,7 +50,10 @@ const DIRECTIVES: Array<Type<void>> = [TimezonePipe, 
I18nElsePipe, ElapsedTimePi
     ...ThirdModules,
     NzBreadCrumbModule,
     NzTagModule,
-    NzDividerComponent
+    NzDividerComponent,
+    NzRadioGroupComponent,
+    NzRadioComponent,
+    NzSwitchComponent
   ],
   declarations: [...COMPONENTS, ...DIRECTIVES, HelpMessageShowComponent],
   exports: [


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to