Quellcode durchsuchen

feat(WecomCenter): redesign UI (card layout) + bundle real Huawei walk template + template switch/migration (preview+confirm)

DSH Agent vor 4 Tagen
Ursprung
Commit
14a0854149

+ 15 - 3
web-modules/README.md

@@ -8,7 +8,8 @@
   - **手动阈值**:勾选会通知的严重度 + 总开关(写媒介 `severity` / `active`)。
 - **优化(Optimization)**
   - **服务端调优生成器**:选“小/中/大”规模,生成 `StartSNMPPollers` 等 `.env`/compose 参数与重建命令——**只生成、不落地**,由运维复制到主机自行重建 server 容器(零风险、零特权)。
-  - **模板导入**:导入 `templates/` 目录里的 yaml/xml/json 模板。
+  - **模板导入**:内置的是**真实的华为模板** `Huawei VRP by SNMP walk`(导出文件在 `templates/`),点“导入”即导入 Zabbix;导入已存在模板会就地更新,导入新模板会新建。
+  - **模板切换(迁移设备)**:选“旧模板 → 新模板”,**预览**列出受影响设备 → **确认切换**把每台设备的模板链接替换为新模板(这就是“导入后是否切换”那一步)。
   - **地图标记**:以 **单点(Zabbix server 主机)** 作为代表点,设置 `location_lat` / `location_lon`。
 - **日常维护(Maintenance)**
   - **触发器告警开关**:按名称搜索触发器,勾选 = 启用告警、取消勾选 = 停用该触发器(写 `trigger.status`,0 启用 / 1 停用)。单套环境常有数万个触发器,需先输入关键字搜索(最多显示 200 条)。
@@ -30,7 +31,7 @@ WecomCenter/
 │   ├── I18n.php                  # 极简多语言层(按当前语言加载,缺省回退英文)
 │   └── Helper.php                # 业务逻辑:媒介/账号/key、方案预设、导入、坐标、测试
 ├── locale/                       # 35 个语言文件(见“多语言”)
-├── templates/demo.yaml           # 示例模板(演示一键导入)
+├── templates/Huawei VRP by SNMP walk.yaml  # 内置真实华为模板(导入/切换用)
 └── assets/wecom.center.css
 ```
 
@@ -121,8 +122,19 @@ WecomCenter/
 - 应用后已做**全量还原**:全部 45,824 行 `priority` 与快照比对 **0 误差**,媒介严重度/策略宏一并复位。证明“一键刷新”在所有探测节点上可运行且**完全可逆**。
 - “预览(dry-run)”按类别列出触发数/将改动数,不写入。已在页面验证渲染正常、无 PHP 报错。
 
+## 模板切换(旧→新迁移)
+
+区别于“导入”,切换是把**已在用的设备**从一个模板迁到另一个模板:
+
+1. 在“优化 → 模板切换”里选 `从模板(旧)` 与 `到模板(新)`(下拉只列 `Huawei` 相关模板)。
+2. 点**预览**:调用 `host.get(templateids=旧)` 列出受影响设备(最多显示 300 个名字)与实际台数,不写入。
+3. 点**确认切换**:对每台设备 `host.update`,把 `templates` 集合中的旧模板替换为新模板(保留其它模板链接、去重)。LLD 会按新模板重新采集。
+4. 页面顶部弹出结果提示(切换了多少台)。
+
+> 实测:`10962(walk) → 10229(旧)` 预览正确显示 **186 device(s)**(带设备名 chips)。当前环境旧模板 10229 挂 0 台,所以反向 `10229 → 10962` 为空操作——这是数据现状,不是功能问题。
+
 ## 已知限制(如实说明)
 
 - **核心 vs 接入的 `Link down` 无法在原型层面区分**(只有一个原型):两者统一设为“一般严重(Average=3)”,71 条核心链路不会被单独拔高;如需对核心链路更敏感,后续可加事件规则/标签区分。
-- **模板“导入后切换”迁移**:当前环境旧模板 `Huawei VRP by SNMP(10229)` 挂载主机数为 0,全部 186 台已在 `Huawei VRP by SNMP walk(10962)`,因此“旧→新迁移”目前是空操作;页面已具备导入能力,若确有旧模板带机迁移需求需再补“切换”逻辑与确认预览。
+- **模板“导入后切换”迁移**:功能已具备(导入 + 预览 + 确认切换)。当前环境旧模板 `Huawei VRP by SNMP(10229)` 挂载主机数为 0,全部 186 台已在 `Huawei VRP by SNMP walk(10962)`,所以“旧→新迁移”在此环境下是空操作;换到真有旧模板带机的环境才会真正迁移。
 - **Geomap 底图**:Zabbix Geomap 组件需**浏览器能访问外网**加载 OSM 瓦片;纯内网环境下底图会空白(标记点逻辑仍正确)。

+ 14 - 0
web-modules/WecomCenter/actions/WecomCenterSave.php

@@ -44,6 +44,7 @@ class WecomCenterSave extends CController {
 					case 'test_robot':      $this->testRobot($mediatypeid); break;
 					case 'import_template': $this->importTemplate();        break;
 					case 'save_map':        $this->saveMap();               break;
+					case 'apply_switch':    $this->applySwitch();           break;
 					default: error(I18n::t('msg.unknown_op'));
 				}
 			}
@@ -178,4 +179,17 @@ class WecomCenterSave extends CController {
 		Helper::setHostLocation($hostid, $lat, $lon);
 		info(I18n::t('msg.map_saved'));
 	}
+
+	private function applySwitch(): void {
+		$src = (string) ($_REQUEST['switch_src'] ?? '');
+		$dst = (string) ($_REQUEST['switch_dst'] ?? '');
+		if ($src === '' || $dst === '') {
+			throw new Exception(I18n::t('msg.need_both'));
+		}
+		if ($src === $dst) {
+			throw new Exception(I18n::t('msg.same_tpl'));
+		}
+		$n = Helper::switchApply($src, $dst);
+		info(I18n::t('msg.switch_applied', [$n]));
+	}
 }

+ 14 - 2
web-modules/WecomCenter/actions/WecomCenterView.php

@@ -74,8 +74,7 @@ class WecomCenterView extends CController {
 		$tuning = Helper::tuningSnippet($tuning_profile);
 
 		// ---- map: single marker = Zabbix server host ----
-		$server_host = null;
-		$server_loc = ['location_lat' => '', 'location_lon' => ''];
+		$server_host = null;		$server_loc = ['location_lat' => '', 'location_lon' => ''];
 		try {
 			$sh = \API::Host()->get([
 				'output'          => ['hostid', 'name'],
@@ -98,6 +97,15 @@ class WecomCenterView extends CController {
 		$triggers = Helper::triggers($trig_search);
 		$trigger_count = Helper::triggerCount();
 
+		// ---- template switch / migration ----
+		$huawei_tpls = Helper::huaweiTemplates();
+		$switch_src = (string) ($_REQUEST['switch_src'] ?? '');
+		$switch_dst = (string) ($_REQUEST['switch_dst'] ?? '');
+		$switch_preview = null;
+		if ($switch_src !== '' && $switch_dst !== '' && $switch_src !== $switch_dst) {
+			$switch_preview = Helper::switchPreview($switch_src, $switch_dst);
+		}
+
 		$data = [
 			'title'           => I18n::t('page.title'),
 			'mediatypes'      => $mediatypes,
@@ -122,6 +130,10 @@ class WecomCenterView extends CController {
 			'trig_search'     => $trig_search,
 			'triggers'        => $triggers,
 			'trigger_count'   => $trigger_count,
+			'huawei_tpls'     => $huawei_tpls,
+			'switch_src'      => $switch_src,
+			'switch_dst'      => $switch_dst,
+			'switch_preview'  => $switch_preview,
 			'lang'            => I18n::lang()
 		];
 

+ 110 - 11
web-modules/WecomCenter/assets/wecom.center.css

@@ -1,12 +1,111 @@
-/* WeCom Center - minimal styling */
-.wecom-center h3 {
-	font-size: 15px;
-	font-weight: 600;
-	margin: 18px 0 8px;
-	border-left: 4px solid #d9534f;
-	padding-left: 8px;
-}
-.wecom-center .preset-buttons .btn {
-	margin-right: 8px;
-	margin-bottom: 8px;
+/* ==================================================================
+   WeCom Center — clean card UI
+   ================================================================== */
+.wc-wrap { padding: 4px 2px 32px; }
+
+.wc-hero {
+	margin: 6px 0 18px;
+	padding: 18px 22px;
+	border-radius: 12px;
+	background: linear-gradient(135deg, #2f6fdd 0%, #274b8f 100%);
+	color: #fff;
+	box-shadow: 0 6px 18px rgba(47,111,221,.25);
 }
+.wc-hero__title { font-size: 20px; font-weight: 700; letter-spacing: .3px; }
+.wc-hero__sub { margin-top: 6px; font-size: 13px; opacity: .9; line-height: 1.5; }
+
+.wc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; align-items: start; }
+
+.wc-card {
+	background: #fff;
+	border: 1px solid #e3e6ea;
+	border-radius: 12px;
+	box-shadow: 0 1px 3px rgba(20,30,50,.06);
+	overflow: hidden;
+	margin-bottom: 16px;
+}
+.wc-card--wide { grid-column: 1 / -1; }
+
+.wc-card__head {
+	display: flex; align-items: center; gap: 10px;
+	padding: 13px 18px;
+	border-bottom: 1px solid #eef0f3;
+	background: #fafbfd;
+}
+.wc-card__ico { font-size: 17px; line-height: 1; }
+.wc-card__title { font-size: 14.5px; font-weight: 650; color: #23272e; }
+.wc-card__sub { font-size: 12px; color: #808793; margin-left: auto; }
+.wc-card__body { padding: 16px 18px; }
+
+.wc-hint { color: #7a828c; font-size: 12px; line-height: 1.6; margin: 0 0 12px; }
+
+/* fields */
+.wc-field { margin-bottom: 14px; }
+.wc-field:last-child { margin-bottom: 0; }
+.wc-field label { display: block; font-size: 12px; font-weight: 600; color: #55606d; margin-bottom: 5px; }
+.wc-input {
+	width: 100%; box-sizing: border-box; padding: 8px 11px;
+	border: 1px solid #cfd6dd; border-radius: 7px; font-size: 13px; color: #23272e; background: #fff;
+}
+.wc-input:focus { outline: none; border-color: #2f6fdd; box-shadow: 0 0 0 3px rgba(47,111,221,.15); }
+.wc-input--mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
+select.wc-input { appearance: auto; }
+
+/* buttons */
+.wc-btn {
+	display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
+	padding: 7px 15px; border-radius: 7px; font-size: 13px; font-weight: 600;
+	border: 1px solid transparent; text-decoration: none !important; line-height: 1.2;
+}
+.wc-btn--primary { background: #2f6fdd; color: #fff; }
+.wc-btn--primary:hover { background: #275fc0; color: #fff; }
+.wc-btn--ghost { background: #fff; color: #2f6fdd; border-color: #cfd6dd; }
+.wc-btn--ghost:hover { background: #f2f6ff; }
+.wc-btn--danger { background: #d9534f; color: #fff; }
+.wc-btn--sm { padding: 5px 11px; font-size: 12px; }
+.wc-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
+
+/* pills & badges */
+.wc-pill { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 600; }
+.wc-pill--cur { background: #e6f4ea; color: #2f9e5e; }
+.wc-pill--muted { background: #eef1f5; color: #667080; }
+.wc-sev { display: inline-block; padding: 1px 8px; border-radius: 5px; font-size: 11.5px; font-weight: 600; color: #fff; }
+.wc-sev-1 { background: #9aa3ad; } .wc-sev-2 { background: #4a90d9; }
+.wc-sev-3 { background: #e0a800; } .wc-sev-4 { background: #e07b00; }
+.wc-sev-5 { background: #d9534f; } .wc-sev-6 { background: #a4133c; }
+
+/* preset rows */
+.wc-preset { display: flex; align-items: center; gap: 14px; padding: 12px 0; border-bottom: 1px solid #f0f2f5; }
+.wc-preset:last-child { border-bottom: none; }
+.wc-preset__main { flex: 1; min-width: 0; }
+.wc-preset__name { font-size: 13.5px; font-weight: 650; color: #23272e; display: flex; align-items: center; gap: 8px; }
+.wc-preset__desc { font-size: 12px; color: #808793; margin-top: 3px; line-height: 1.45; }
+.wc-preset__act { display: flex; gap: 8px; flex-shrink: 0; }
+
+/* tables */
+.wc-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
+.wc-table th { text-align: left; padding: 9px 10px; background: #f7f9fc; color: #667080; font-weight: 600; border-bottom: 1px solid #e6eaef; white-space: nowrap; }
+.wc-table td { padding: 9px 10px; border-bottom: 1px solid #eef1f4; color: #2b2f36; vertical-align: middle; }
+.wc-table tr:last-child td { border-bottom: none; }
+.wc-table .num { text-align: right; font-variant-numeric: tabular-nums; }
+.wc-table tr.wc-tr-total td { background: #fafbfd; font-weight: 700; }
+
+/* code block */
+.wc-code { background: #0f172a; color: #e2e8f0; padding: 13px 15px; border-radius: 9px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; line-height: 1.6; overflow: auto; white-space: pre; margin: 8px 0 14px; }
+.wc-code__label { font-size: 12px; font-weight: 600; color: #55606d; margin: 2px 0 2px; }
+
+/* checkbox list */
+.wc-checks { display: flex; flex-wrap: wrap; gap: 10px 18px; }
+.wc-checks label { display inline; font-weight: 500; color: #2b2f36; font-size: 12.5px; }
+.wc-checkrow { display: flex; align-items: center; gap: 8px; }
+
+/* host chips (preview) */
+.wc-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
+.wc-chip { background: #eef4ff; color: #274b8f; border-radius: 6px; padding: 3px 9px; font-size: 11.5px; }
+
+/* misc */
+.wc-muted { color: #808793; font-size: 12px; }
+.wc-divider { height: 1px; background: #eef1f4; margin: 16px 0; }
+.wc-empty { color: #808793; font-size: 13px; padding: 10px 0; }
+.wc-inline { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
+.wc-inline .wc-field { flex: 1; min-width: 160px; margin-bottom: 0; }

+ 88 - 0
web-modules/WecomCenter/lib/Helper.php

@@ -744,4 +744,92 @@ class Helper {
 			."cd /opt/zabbix && docker compose up -d zabbix-server";
 		return ['env' => $env, 'cmd' => $cmd];
 	}
+
+	/* ================================================================== */
+	/*  TEMPLATE SWITCH / MIGRATION (old template -> new template)        */
+	/* ================================================================== */
+
+	/** Huawei-related templates available on this server (source/target candidates). */
+	public static function huaweiTemplates(): array {
+		try {
+			$res = API::Template()->get([
+				'output'    => ['templateid', 'host', 'name'],
+				'search'    => ['host' => 'Huawei'],
+				'sortfield' => 'host'
+			]);
+			return $res ?: [];
+		}
+		catch (\Throwable $e) {
+			return [];
+		}
+	}
+
+	/** Hosts currently linked to the given template. */
+	public static function hostsOnTemplate(string $tid): array {
+		$res = API::Host()->get([
+			'output'                => ['hostid', 'host', 'name'],
+			'templateids'           => [$tid],
+			'selectParentTemplates' => ['templateid'],
+			'sortfield'             => 'name'
+		]);
+		return $res ?: [];
+	}
+
+	public static function templateNames(array $ids): array {
+		$out = [];
+		if (!$ids) {
+			return $out;
+		}
+		$res = API::Template()->get(['output' => ['templateid', 'host'], 'templateids' => $ids]);
+		foreach ($res as $t) {
+			$out[$t['templateid']] = $t['host'];
+		}
+		return $out;
+	}
+
+	/** Dry-run: which hosts would move from $src to $dst. */
+	public static function switchPreview(string $src, string $dst): array {
+		$hosts = self::hostsOnTemplate($src);
+		$names = [];
+		foreach ($hosts as $h) {
+			$names[] = ($h['name'] !== '') ? $h['name'] : $h['host'];
+		}
+		$tn = self::templateNames([$src, $dst]);
+		return [
+			'src'      => $src,
+			'dst'      => $dst,
+			'src_name' => $tn[$src] ?? $src,
+			'dst_name' => $tn[$dst] ?? $dst,
+			'count'    => count($hosts),
+			'hosts'    => array_slice($names, 0, 300)
+		];
+	}
+
+	/** Replace the source template link with the target for every host on source. */
+	public static function switchApply(string $src, string $dst): int {
+		if ($src === $dst) {
+			throw new Exception('Source and target template are the same.');
+		}
+		$hosts = self::hostsOnTemplate($src);
+		$n = 0;
+		foreach ($hosts as $h) {
+			$new = [];
+			$has_dst = false;
+			foreach (($h['parentTemplates'] ?? []) as $pt) {
+				if ((string) $pt['templateid'] === $src) {
+					continue;
+				}
+				if ((string) $pt['templateid'] === $dst) {
+					$has_dst = true;
+				}
+				$new[] = ['templateid' => $pt['templateid']];
+			}
+			if (!$has_dst) {
+				$new[] = ['templateid' => $dst];
+			}
+			API::Host()->update(['hostid' => $h['hostid'], 'templates' => $new]);
+			$n++;
+		}
+		return $n;
+	}
 }

+ 15 - 0
web-modules/WecomCenter/locale/en.php

@@ -119,4 +119,19 @@ return [
 	'msg.triggers_saved' => 'Trigger alerting updated: {1} trigger(s).',
 	'msg.no_trig_search' => 'No triggers matched your search.',
 	'msg.strategy_applied' => 'Strategy "{1}" applied — template triggers: {2}, prototypes: {3}, discovered triggers: {4}.',
+
+	// hero + template switch
+	'hero.sub'        => 'WeCom group alerts, one-click alert strategy, server tuning, template migration and per-trigger control — all in one place.',
+	'lbl.template_hint' => 'Bundled templates ship with the module. Importing an existing template updates it in place; importing a new one creates it. Use the switch card below to move devices from an old template to the new one.',
+	'sec.switch'      => 'Template switch (migrate devices)',
+	'lbl.switch_hint' => 'Pick the OLD template and the NEW template. Preview lists the affected devices; confirm replaces the template link on every one of them. This is the "import, then switch?" step.',
+	'switch.pick'     => '-- select template --',
+	'switch.src'      => 'From template (old)',
+	'switch.dst'      => 'To template (new)',
+	'switch.none'     => 'No device currently uses "{1}". Nothing to switch.',
+	'switch.result'   => '{1} device(s) on "{2}" will be moved to "{3}".',
+	'btn.confirm'     => 'Confirm switch',
+	'msg.need_both'   => 'Please choose both source and target template.',
+	'msg.same_tpl'    => 'Source and target template must differ.',
+	'msg.switch_applied' => 'Switched {1} device(s) to the new template.',
 ];

+ 14 - 0
web-modules/WecomCenter/locale/zh_CN.php

@@ -107,4 +107,18 @@ return [
 	'msg.triggers_saved' => '触发器告警已更新:{1} 个。',
 	'msg.no_trig_search' => '没有匹配的触发器。',
 	'msg.strategy_applied' => '策略“{1}”已应用 —— 模板触发器:{2},触发器原型:{3},发现触发器:{4}。',
+
+	'hero.sub'        => '企业微信群告警、一键告警策略、服务端调优、模板迁移与逐条控制,全部集中在这里。',
+	'lbl.template_hint' => '内置模板随模块一起提供。导入已存在的模板会就地更新;导入新模板会新建。下方“模板切换”卡片可把设备从旧模板迁到新模板。',
+	'sec.switch'      => '模板切换(迁移设备)',
+	'lbl.switch_hint' => '选择“旧模板”和“新模板”。预览会列出受影响的设备;确认后把每一台设备的模板链接替换为新模板。这就是“导入后是否切换”那一步。',
+	'switch.pick'     => '-- 选择模板 --',
+	'switch.src'      => '从模板(旧)',
+	'switch.dst'      => '到模板(新)',
+	'switch.none'     => '当前没有设备使用“{1}”,无需切换。',
+	'switch.result'   => '将把“{2}”上的 {1} 台设备迁移到“{3}”。',
+	'btn.confirm'     => '确认切换',
+	'msg.need_both'   => '请同时选择源模板与目标模板。',
+	'msg.same_tpl'    => '源模板与目标模板必须不同。',
+	'msg.switch_applied' => '已切换 {1} 台设备到新模板。',
 ];

+ 1759 - 0
web-modules/WecomCenter/templates/Huawei VRP by SNMP walk.yaml

@@ -0,0 +1,1759 @@
+zabbix_export:
+  version: '7.4'
+  template_groups:
+    - uuid: 36bff6c29af64692839d077febfc7079
+      name: 'Templates/Network devices'
+  templates:
+    - uuid: 40d1a1341f2641078acfb277da86503a
+      template: 'Huawei VRP by SNMP walk'
+      name: 'Huawei VRP by SNMP (walk)'
+      description: |
+        Huawei VRP SNMP template (walk + dependent items).
+        
+        Interface monitoring uses ONE SNMP bulk-walk master item (net.if.walk) plus a dependent LLD rule and 9 dependent item prototype families (status/type/speed/in/out/in.errors/out.errors/in.discards/out.discards), replacing legacy per-OID GetRequest polling. Per host SNMP interface requests drop from ~1962/OID-items to 1 bulk walk, cutting SNMP load by ~99% and eliminating down-port timeout storms.
+        
+        MIBs used:
+        HUAWEI-ENTITY-MIB, HUAWEI-ENTITY-STATE-MIB, HUAWEI-ENTITY-EXTENT-MIB, IF-MIB, SNMPv2-MIB, HOST-RESOURCES-MIB
+      vendor:
+        name: FlyingRome
+        version: 7.4-walk-1
+      groups:
+        - name: 'Templates/Network devices'
+      items:
+        - uuid: 66a5700949894b9a97b666c3444296a8
+          name: 'ICMP ping'
+          type: SIMPLE
+          key: icmpping
+          description: |
+            The host accessibility by ICMP ping.
+            
+            0 - ICMP ping fails;
+            1 - ICMP ping successful.
+          valuemap:
+            name: 'Service state'
+          tags:
+            - tag: component
+              value: health
+            - tag: component
+              value: network
+          triggers:
+            - uuid: ca85dce96dd24ef89b5379de9e848ee2
+              expression: 'max(/Huawei VRP by SNMP walk/icmpping,#3)=0'
+              name: 'Huawei VRP: Unavailable by ICMP ping'
+              priority: HIGH
+              description: 'Last three attempts returned timeout. Please check device connectivity.'
+              tags:
+                - tag: scope
+                  value: availability
+        - uuid: 0b45cf586b49426eb9249f1773ae4b27
+          name: 'ICMP loss'
+          type: SIMPLE
+          key: icmppingloss
+          value_type: FLOAT
+          units: '%'
+          description: 'The percentage of lost packets.'
+          tags:
+            - tag: component
+              value: health
+            - tag: component
+              value: network
+          triggers:
+            - uuid: 9bcb0ab4ebf343c4ba2b0db9222dcf66
+              expression: 'min(/Huawei VRP by SNMP walk/icmppingloss,5m)>{$ICMP_LOSS_WARN} and min(/Huawei VRP by SNMP walk/icmppingloss,5m)<100'
+              name: 'Huawei VRP: High ICMP ping loss'
+              opdata: 'Loss: {ITEM.LASTVALUE1}'
+              priority: WARNING
+              description: 'ICMP packets loss detected.'
+              dependencies:
+                - name: 'Huawei VRP: Unavailable by ICMP ping'
+                  expression: 'max(/Huawei VRP by SNMP walk/icmpping,#3)=0'
+              tags:
+                - tag: scope
+                  value: availability
+                - tag: scope
+                  value: performance
+        - uuid: bb489af217914297a49bf3afe71fd7f8
+          name: 'ICMP response time'
+          type: SIMPLE
+          key: icmppingsec
+          value_type: FLOAT
+          units: s
+          description: 'The ICMP ping response time (in seconds).'
+          tags:
+            - tag: component
+              value: health
+            - tag: component
+              value: network
+          triggers:
+            - uuid: 1547e194eaa3441db5230c422db84cfd
+              expression: 'avg(/Huawei VRP by SNMP walk/icmppingsec,5m)>{$ICMP_RESPONSE_TIME_WARN}'
+              name: 'Huawei VRP: High ICMP ping response time'
+              opdata: 'Value: {ITEM.LASTVALUE1}'
+              priority: WARNING
+              description: 'Average ICMP response time is too high.'
+              dependencies:
+                - name: 'Huawei VRP: High ICMP ping loss'
+                  expression: 'min(/Huawei VRP by SNMP walk/icmppingloss,5m)>{$ICMP_LOSS_WARN} and min(/Huawei VRP by SNMP walk/icmppingloss,5m)<100'
+                - name: 'Huawei VRP: Unavailable by ICMP ping'
+                  expression: 'max(/Huawei VRP by SNMP walk/icmpping,#3)=0'
+              tags:
+                - tag: scope
+                  value: availability
+                - tag: scope
+                  value: performance
+        - uuid: e3f43884604042d8b482617356130cbe
+          name: 'Huawei VRP: SNMP walk network interfaces'
+          type: SNMP_AGENT
+          snmp_oid: 'walk[1.3.6.1.2.1.2.2.1.8,1.3.6.1.2.1.2.2.1.7,1.3.6.1.2.1.31.1.1.1.18,1.3.6.1.2.1.31.1.1.1.1,1.3.6.1.2.1.2.2.1.2,1.3.6.1.2.1.2.2.1.3,1.3.6.1.2.1.31.1.1.1.6,1.3.6.1.2.1.31.1.1.1.10,1.3.6.1.2.1.2.2.1.14,1.3.6.1.2.1.2.2.1.20,1.3.6.1.2.1.2.2.1.19,1.3.6.1.2.1.2.2.1.13,1.3.6.1.2.1.31.1.1.1.15]'
+          key: net.if.walk
+          history: '0'
+          value_type: TEXT
+          description: 'Discovering interfaces from IF-MIB.'
+          timeout: 30s
+          tags:
+            - tag: component
+              value: raw
+        - uuid: e2668029062647b19875e88eebc2d3ef
+          name: 'SNMP traps (fallback)'
+          type: SNMP_TRAP
+          key: snmptrap.fallback
+          value_type: LOG
+          description: 'The item is used to collect all SNMP traps unmatched by other snmptrap items'
+          logtimefmt: 'hh:mm:sszyyyy/MM/dd'
+          tags:
+            - tag: component
+              value: network
+        - uuid: af9eb08ab9ad47a694322b038fff2e56
+          name: 'System contact details'
+          type: SNMP_AGENT
+          snmp_oid: 'get[1.3.6.1.2.1.1.4.0]'
+          key: 'system.contact[sysContact.0]'
+          delay: 15m
+          value_type: CHAR
+          description: |
+            MIB: SNMPv2-MIB
+            The textual identification of the contact person for this managed node, together with information on how to contact this person. If no contact information is known, the value is the zero-length string.
+          inventory_link: CONTACT
+          preprocessing:
+            - type: DISCARD_UNCHANGED_HEARTBEAT
+              parameters:
+                - 12h
+          tags:
+            - tag: component
+              value: system
+        - uuid: 8c8bffb726ae44069becad2d4f4d87e9
+          name: 'System description'
+          type: SNMP_AGENT
+          snmp_oid: 'get[1.3.6.1.2.1.1.1.0]'
+          key: 'system.descr[sysDescr.0]'
+          delay: 15m
+          value_type: CHAR
+          description: |
+            MIB: SNMPv2-MIB
+            A textual description of the entity. This value should
+            include the full name and version identification of the system's hardware type, software operating-system, and
+            networking software.
+          preprocessing:
+            - type: DISCARD_UNCHANGED_HEARTBEAT
+              parameters:
+                - 12h
+          tags:
+            - tag: component
+              value: system
+        - uuid: 857d11b88f8145609bba2dc15a5f5702
+          name: 'Uptime (hardware)'
+          type: SNMP_AGENT
+          snmp_oid: 'get[1.3.6.1.2.1.25.1.1.0]'
+          key: 'system.hw.uptime[hrSystemUptime.0]'
+          delay: 30s
+          trends: '0'
+          units: uptime
+          description: |
+            MIB: HOST-RESOURCES-MIB
+            The amount of time since this host was last initialized. Note that this is different from sysUpTime in the SNMPv2-MIB [RFC1907] because sysUpTime is the uptime of the network management portion of the system.
+          preprocessing:
+            - type: CHECK_NOT_SUPPORTED
+              parameters:
+                - '-1'
+              error_handler: CUSTOM_VALUE
+              error_handler_params: '0'
+            - type: MULTIPLIER
+              parameters:
+                - '0.01'
+          tags:
+            - tag: component
+              value: system
+        - uuid: b50bec28e6804e699bd1e7f205cb7b1b
+          name: 'System location'
+          type: SNMP_AGENT
+          snmp_oid: 'get[1.3.6.1.2.1.1.6.0]'
+          key: 'system.location[sysLocation.0]'
+          delay: 15m
+          value_type: CHAR
+          description: |
+            MIB: SNMPv2-MIB
+            Physical location of the node (e.g., `equipment room`, `3rd floor`). If not provided, the value is a zero-length string.
+          inventory_link: LOCATION
+          preprocessing:
+            - type: DISCARD_UNCHANGED_HEARTBEAT
+              parameters:
+                - 12h
+          tags:
+            - tag: component
+              value: system
+        - uuid: 2d7e9f35b1954758858604c72111aff1
+          name: 'System name'
+          type: SNMP_AGENT
+          snmp_oid: 'get[1.3.6.1.2.1.1.5.0]'
+          key: system.name
+          delay: 15m
+          value_type: CHAR
+          description: |
+            MIB: SNMPv2-MIB
+            An administratively-assigned name for this managed node.By convention, this is the node's fully-qualified domain name. If the name is unknown, the value is the zero-length string.
+          inventory_link: NAME
+          preprocessing:
+            - type: DISCARD_UNCHANGED_HEARTBEAT
+              parameters:
+                - 12h
+          tags:
+            - tag: component
+              value: system
+          triggers:
+            - uuid: 71fa72cc741c40f3a31d1a6f9f26d401
+              expression: 'last(/Huawei VRP by SNMP walk/system.name,#1)<>last(/Huawei VRP by SNMP walk/system.name,#2) and length(last(/Huawei VRP by SNMP walk/system.name))>0'
+              name: 'Huawei VRP: System name has changed'
+              event_name: 'Huawei VRP: System name has changed (new name: {ITEM.VALUE})'
+              priority: INFO
+              description: 'The name of the system has changed. Acknowledge to close the problem manually.'
+              manual_close: 'YES'
+              tags:
+                - tag: scope
+                  value: notice
+                - tag: scope
+                  value: security
+        - uuid: e7ceae2ca308474796f48e310fc98412
+          name: 'Uptime (network)'
+          type: SNMP_AGENT
+          snmp_oid: 'get[1.3.6.1.2.1.1.3.0]'
+          key: 'system.net.uptime[sysUpTime.0]'
+          delay: 30s
+          trends: '0'
+          units: uptime
+          description: |
+            MIB: SNMPv2-MIB
+            Time (in hundredths of a second) since the network management portion of the system was last re-initialized.
+          preprocessing:
+            - type: MULTIPLIER
+              parameters:
+                - '0.01'
+          tags:
+            - tag: component
+              value: system
+        - uuid: 2a6cd1a6a5b149e3be8dfa343f9f0227
+          name: 'System object ID'
+          type: SNMP_AGENT
+          snmp_oid: 'get[1.3.6.1.2.1.1.2.0]'
+          key: 'system.objectid[sysObjectID.0]'
+          delay: 15m
+          value_type: CHAR
+          description: |
+            MIB: SNMPv2-MIB
+            The vendor's authoritative identification of the network management subsystem contained in the entity. This value is allocated within the SMI enterprises subtree (1.3.6.1.4.1) and provides an easy and unambiguous means for determining`what kind of box' is being managed.  For example, if vendor`Flintstones, Inc.' was assigned the subtree1.3.6.1.4.1.4242, it could assign the identifier 1.3.6.1.4.1.4242.1.1 to its `Fred Router'.
+          preprocessing:
+            - type: DISCARD_UNCHANGED_HEARTBEAT
+              parameters:
+                - 12h
+          tags:
+            - tag: component
+              value: system
+        - uuid: 94df7b0547d2464d9c50c82e63bfb956
+          name: 'SNMP agent availability'
+          type: INTERNAL
+          key: 'zabbix[host,snmp,available]'
+          description: |
+            Availability of SNMP checks on the host. The value of this item corresponds to availability icons in the host list.
+            Possible values:
+            0 - not available
+            1 - available
+            2 - unknown
+          valuemap:
+            name: zabbix.host.available
+          tags:
+            - tag: component
+              value: health
+            - tag: component
+              value: network
+          triggers:
+            - uuid: aa4153beff3c4316b3acb0cc41f5a57d
+              expression: 'max(/Huawei VRP by SNMP walk/zabbix[host,snmp,available],{$SNMP.TIMEOUT})=0'
+              name: 'Huawei VRP: No SNMP data collection'
+              opdata: 'Current state: {ITEM.LASTVALUE1}'
+              priority: WARNING
+              description: 'SNMP is not available for polling. Please check device connectivity and SNMP settings.'
+              dependencies:
+                - name: 'Huawei VRP: Unavailable by ICMP ping'
+                  expression: 'max(/Huawei VRP by SNMP walk/icmpping,#3)=0'
+              tags:
+                - tag: scope
+                  value: availability
+      discovery_rules:
+        - uuid: 184452e88e274d84adc11e36e5765722
+          name: 'FAN Discovery'
+          type: SNMP_AGENT
+          snmp_oid: 'discovery[{#SNMPVALUE},1.3.6.1.4.1.2011.5.25.31.1.1.10.1.1]'
+          key: discovery.fans
+          delay: 1h
+          item_prototypes:
+            - uuid: 30a53d67f33b45e7bc2f4cc22e24dae3
+              name: '#{#SNMPVALUE}: Fan status'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.4.1.2011.5.25.31.1.1.10.1.7.{#SNMPINDEX}]'
+              key: 'sensor.fan.status[hwEntityFanState.{#SNMPINDEX}]'
+              delay: 3m
+              trends: '0'
+              description: 'MIB: HUAWEI-ENTITY-EXTENT-MIB'
+              valuemap:
+                name: 'HUAWEI-ENTITY-EXTENT-MIB::hwEntityFanState'
+              tags:
+                - tag: component
+                  value: fan
+              trigger_prototypes:
+                - uuid: be04433dacce45a5b8f09607bbb51865
+                  expression: 'count(/Huawei VRP by SNMP walk/sensor.fan.status[hwEntityFanState.{#SNMPINDEX}],#1,"eq","{$FAN_CRIT_STATUS}")=1'
+                  name: 'Huawei VRP: #{#SNMPVALUE}: Fan is in critical state'
+                  opdata: 'Current state: {ITEM.LASTVALUE1}'
+                  priority: AVERAGE
+                  description: 'Please check the fan unit'
+                  tags:
+                    - tag: scope
+                      value: availability
+                    - tag: scope
+                      value: performance
+        - uuid: 96eabf2799d04c63bb6049b34823f280
+          name: 'Entity Discovery'
+          type: SNMP_AGENT
+          snmp_oid: 'discovery[{#ENT_CLASS},1.3.6.1.2.1.47.1.1.1.1.5,{#ENT_NAME},1.3.6.1.2.1.47.1.1.1.1.7]'
+          key: entity.discovery
+          delay: 1h
+          filter:
+            conditions:
+              - macro: '{#ENT_CLASS}'
+                value: '3'
+          item_prototypes:
+            - uuid: 1f99535288154bf19cace8de374fc6f8
+              name: '{#ENT_NAME}: Hardware model name'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.2.1.47.1.1.1.1.2.{#SNMPINDEX}]'
+              key: 'system.hw.model[entPhysicalDescr.{#SNMPINDEX}]'
+              delay: 1h
+              value_type: CHAR
+              description: 'MIB: ENTITY-MIB'
+              preprocessing:
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 1d
+              tags:
+                - tag: component
+                  value: system
+        - uuid: 9187e4d0fd754da0b53090542ed8bf0e
+          name: 'MPU Discovery'
+          type: SNMP_AGENT
+          snmp_oid: 'discovery[{#ENT_NAME},1.3.6.1.2.1.47.1.1.1.1.7]'
+          key: mpu.discovery
+          delay: 1h
+          filter:
+            conditions:
+              - macro: '{#ENT_NAME}'
+                value: 'MPU.*'
+          description: 'http://support.huawei.com/enterprise/KnowledgebaseReadAction.action?contentId=KB1000090234. Filter limits results to Main Processing Units'
+          item_prototypes:
+            - uuid: c68271a839cd4ad3ae222876355ef16c
+              name: '{#ENT_NAME}: Temperature'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.4.1.2011.5.25.31.1.1.1.1.11.{#SNMPINDEX}]'
+              key: 'sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}]'
+              delay: 3m
+              value_type: FLOAT
+              units: °C
+              description: |
+                MIB: HUAWEI-ENTITY-EXTENT-MIB
+                The temperature for the {#SNMPVALUE}.
+              tags:
+                - tag: component
+                  value: temperature
+              trigger_prototypes:
+                - uuid: 3d9c23a3fd5d4c46959fe8fcd8d91d72
+                  expression: 'avg(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)>{$TEMP_CRIT:"{#ENT_NAME}"}'
+                  recovery_mode: RECOVERY_EXPRESSION
+                  recovery_expression: 'max(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)<{$TEMP_CRIT:"{#ENT_NAME}"}-3'
+                  name: 'Huawei VRP: {#ENT_NAME}: Temperature is above critical threshold'
+                  event_name: 'Huawei VRP: {#ENT_NAME}: Temperature is above critical threshold: >{$TEMP_CRIT:"{#ENT_NAME}"}'
+                  opdata: 'Current value: {ITEM.LASTVALUE1}'
+                  priority: HIGH
+                  description: 'This trigger uses temperature sensor values as well as temperature sensor status if available'
+                  tags:
+                    - tag: scope
+                      value: availability
+                    - tag: scope
+                      value: performance
+                - uuid: baa9c0c42cc94daebb7aff5ea6099941
+                  expression: 'avg(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)>{$TEMP_WARN:"{#ENT_NAME}"}'
+                  recovery_mode: RECOVERY_EXPRESSION
+                  recovery_expression: 'max(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)<{$TEMP_WARN:"{#ENT_NAME}"}-3'
+                  name: 'Huawei VRP: {#ENT_NAME}: Temperature is above warning threshold'
+                  event_name: 'Huawei VRP: {#ENT_NAME}: Temperature is above warning threshold: >{$TEMP_WARN:"{#ENT_NAME}"}'
+                  opdata: 'Current value: {ITEM.LASTVALUE1}'
+                  priority: WARNING
+                  description: 'This trigger uses temperature sensor values as well as temperature sensor status if available'
+                  dependencies:
+                    - name: 'Huawei VRP: {#ENT_NAME}: Temperature is above critical threshold'
+                      expression: 'avg(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)>{$TEMP_CRIT:"{#ENT_NAME}"}'
+                      recovery_expression: 'max(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)<{$TEMP_CRIT:"{#ENT_NAME}"}-3'
+                  tags:
+                    - tag: scope
+                      value: availability
+                    - tag: scope
+                      value: performance
+                - uuid: 6e7ff7a1e277497480d1c466029160a0
+                  expression: '(avg(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)<{$TEMP_CRIT_LOW:"{#ENT_NAME}"}) and (avg(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)>0)'
+                  recovery_mode: RECOVERY_EXPRESSION
+                  recovery_expression: 'min(/Huawei VRP by SNMP walk/sensor.temp.value[hwEntityTemperature.{#SNMPINDEX}],5m)>{$TEMP_CRIT_LOW:"{#ENT_NAME}"}+3'
+                  name: 'Huawei VRP: {#ENT_NAME}: Temperature is too low'
+                  event_name: 'Huawei VRP: {#ENT_NAME}: Temperature is too low: <{$TEMP_CRIT_LOW:"{#ENT_NAME}"}'
+                  opdata: 'Current value: {ITEM.LASTVALUE1}'
+                  priority: AVERAGE
+                  manual_close: 'YES'
+                  tags:
+                    - tag: scope
+                      value: availability
+                    - tag: scope
+                      value: performance
+            - uuid: 302142d000954fb8b5ac0f9221734109
+              name: '{#ENT_NAME}: CPU utilization'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.4.1.2011.5.25.31.1.1.1.1.5.{#SNMPINDEX}]'
+              key: 'system.cpu.util[hwEntityCpuUsage.{#SNMPINDEX}]'
+              value_type: FLOAT
+              units: '%'
+              description: |
+                MIB: HUAWEI-ENTITY-EXTENT-MIB
+                The CPU usage for this entity. Generally, the CPU usage will calculate the overall CPU usage on the entity, and itis not sensible with the number of CPU on the entity.
+                Reference: http://support.huawei.com/enterprise/KnowledgebaseReadAction.action?contentId=KB1000090234
+              tags:
+                - tag: component
+                  value: cpu
+              trigger_prototypes:
+                - uuid: b2dd898af4d44a008fe1e3d0709b09e1
+                  expression: 'min(/Huawei VRP by SNMP walk/system.cpu.util[hwEntityCpuUsage.{#SNMPINDEX}],5m)>{$CPU.UTIL.CRIT}'
+                  name: 'Huawei VRP: {#ENT_NAME}: High CPU utilization'
+                  event_name: 'Huawei VRP: {#ENT_NAME}: High CPU utilization (over {$CPU.UTIL.CRIT}% for 5m)'
+                  opdata: 'Current utilization: {ITEM.LASTVALUE1}'
+                  priority: WARNING
+                  description: 'The CPU utilization is too high. The system might be slow to respond.'
+                  tags:
+                    - tag: scope
+                      value: performance
+            - uuid: 9ae8cc60d36e472cbc7fbb3c73c6dfab
+              name: '{#ENT_NAME}: Hardware serial number'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.2.1.47.1.1.1.1.11.{#SNMPINDEX}]'
+              key: 'system.hw.serialnumber[entPhysicalSerialNum.{#SNMPINDEX}]'
+              delay: 1h
+              value_type: CHAR
+              description: 'MIB: ENTITY-MIB'
+              preprocessing:
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 1d
+              tags:
+                - tag: component
+                  value: system
+              trigger_prototypes:
+                - uuid: 2cce2b9d0eec4abf9fc42f5cfb79aac9
+                  expression: 'last(/Huawei VRP by SNMP walk/system.hw.serialnumber[entPhysicalSerialNum.{#SNMPINDEX}],#1)<>last(/Huawei VRP by SNMP walk/system.hw.serialnumber[entPhysicalSerialNum.{#SNMPINDEX}],#2) and length(last(/Huawei VRP by SNMP walk/system.hw.serialnumber[entPhysicalSerialNum.{#SNMPINDEX}]))>0'
+                  name: 'Huawei VRP: {#ENT_NAME}: Device has been replaced'
+                  event_name: 'Huawei VRP: {#ENT_NAME}: Device has been replaced (new serial number received)'
+                  priority: INFO
+                  description: 'Device serial number has changed. Acknowledge to close the problem manually.'
+                  manual_close: 'YES'
+                  tags:
+                    - tag: scope
+                      value: notice
+            - uuid: cd41e6d561684d2c8a830661f85d8f97
+              name: '{#ENT_NAME}: Hardware version(revision)'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.2.1.47.1.1.1.1.8.{#SNMPINDEX}]'
+              key: 'system.hw.version[entPhysicalHardwareRev.{#SNMPINDEX}]'
+              delay: 1h
+              value_type: CHAR
+              description: 'MIB: ENTITY-MIB'
+              preprocessing:
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 1d
+              tags:
+                - tag: component
+                  value: system
+            - uuid: e5ca46bbd64f4e9c9fb98704ec429860
+              name: '{#ENT_NAME}: Operating system'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.2.1.47.1.1.1.1.10.{#SNMPINDEX}]'
+              key: 'system.sw.os[entPhysicalSoftwareRev.{#SNMPINDEX}]'
+              delay: 1h
+              value_type: CHAR
+              description: 'MIB: ENTITY-MIB'
+              preprocessing:
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 1d
+              tags:
+                - tag: component
+                  value: os
+              trigger_prototypes:
+                - uuid: 57795727a6c34d90853c38ecee5d2d73
+                  expression: 'last(/Huawei VRP by SNMP walk/system.sw.os[entPhysicalSoftwareRev.{#SNMPINDEX}],#1)<>last(/Huawei VRP by SNMP walk/system.sw.os[entPhysicalSoftwareRev.{#SNMPINDEX}],#2) and length(last(/Huawei VRP by SNMP walk/system.sw.os[entPhysicalSoftwareRev.{#SNMPINDEX}]))>0'
+                  name: 'Huawei VRP: {#ENT_NAME}: Operating system description has changed'
+                  priority: INFO
+                  description: 'Operating system description has changed. Possible reasons that system has been updated or replaced. Acknowledge to close the problem manually.'
+                  manual_close: 'YES'
+                  dependencies:
+                    - name: 'Huawei VRP: System name has changed'
+                      expression: 'last(/Huawei VRP by SNMP walk/system.name,#1)<>last(/Huawei VRP by SNMP walk/system.name,#2) and length(last(/Huawei VRP by SNMP walk/system.name))>0'
+                  tags:
+                    - tag: scope
+                      value: notice
+            - uuid: 0ee11d74257b4db1974b2f438c3392c5
+              name: '{#ENT_NAME}: Memory utilization'
+              type: SNMP_AGENT
+              snmp_oid: 'get[1.3.6.1.4.1.2011.5.25.31.1.1.1.1.7.{#SNMPINDEX}]'
+              key: 'vm.memory.util[hwEntityMemUsage.{#SNMPINDEX}]'
+              value_type: FLOAT
+              units: '%'
+              description: |
+                MIB: HUAWEI-ENTITY-EXTENT-MIB
+                The memory usage for the entity. This object indicates what percent of memory are used.
+                Reference: http://support.huawei.com/enterprise/KnowledgebaseReadAction.action?contentId=KB1000090234
+              tags:
+                - tag: component
+                  value: memory
+              trigger_prototypes:
+                - uuid: a2cc6fca4c204f729bc34c15b33666c2
+                  expression: 'min(/Huawei VRP by SNMP walk/vm.memory.util[hwEntityMemUsage.{#SNMPINDEX}],5m)>{$MEMORY.UTIL.MAX}'
+                  name: 'Huawei VRP: {#ENT_NAME}: High memory utilization'
+                  event_name: 'Huawei VRP: {#ENT_NAME}: High memory utilization (>{$MEMORY.UTIL.MAX}% for 5m)'
+                  priority: AVERAGE
+                  description: 'The system is running out of free memory.'
+                  tags:
+                    - tag: scope
+                      value: capacity
+                    - tag: scope
+                      value: performance
+          graph_prototypes:
+            - uuid: 29486f8318e4494a9f87a8684a82a1dd
+              name: '{#ENT_NAME}: CPU utilization'
+              ymin_type_1: FIXED
+              ymax_type_1: FIXED
+              graph_items:
+                - drawtype: GRADIENT_LINE
+                  color: 199C0D
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'system.cpu.util[hwEntityCpuUsage.{#SNMPINDEX}]'
+            - uuid: 9a56bbd1cd0a4f9fb905df939daf46f1
+              name: '{#ENT_NAME}: Memory utilization'
+              ymin_type_1: FIXED
+              ymax_type_1: FIXED
+              graph_items:
+                - drawtype: GRADIENT_LINE
+                  color: 199C0D
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'vm.memory.util[hwEntityMemUsage.{#SNMPINDEX}]'
+        - uuid: 4ad45aa92654486ea64ca03560b16c5c
+          name: 'Network interfaces discovery'
+          type: DEPENDENT
+          key: net.if.discovery
+          filter:
+            evaltype: AND
+            conditions:
+              - macro: '{#IFADMINSTATUS}'
+                value: '{$NET.IF.IFADMINSTATUS.MATCHES}'
+              - macro: '{#IFADMINSTATUS}'
+                value: '{$NET.IF.IFADMINSTATUS.NOT_MATCHES}'
+                operator: NOT_MATCHES_REGEX
+              - macro: '{#IFALIAS}'
+                value: '{$NET.IF.IFALIAS.MATCHES}'
+              - macro: '{#IFALIAS}'
+                value: '{$NET.IF.IFALIAS.NOT_MATCHES}'
+                operator: NOT_MATCHES_REGEX
+              - macro: '{#IFDESCR}'
+                value: '{$NET.IF.IFDESCR.MATCHES}'
+              - macro: '{#IFDESCR}'
+                value: '{$NET.IF.IFDESCR.NOT_MATCHES}'
+                operator: NOT_MATCHES_REGEX
+              - macro: '{#IFNAME}'
+                value: '{$NET.IF.IFNAME.MATCHES}'
+              - macro: '{#IFNAME}'
+                value: '{$NET.IF.IFNAME.NOT_MATCHES}'
+                operator: NOT_MATCHES_REGEX
+              - macro: '{#IFOPERSTATUS}'
+                value: '{$NET.IF.IFOPERSTATUS.MATCHES}'
+              - macro: '{#IFOPERSTATUS}'
+                value: '{$NET.IF.IFOPERSTATUS.NOT_MATCHES}'
+                operator: NOT_MATCHES_REGEX
+              - macro: '{#IFTYPE}'
+                value: '{$NET.IF.IFTYPE.MATCHES}'
+              - macro: '{#IFTYPE}'
+                value: '{$NET.IF.IFTYPE.NOT_MATCHES}'
+                operator: NOT_MATCHES_REGEX
+          description: 'Discovering interfaces from IF-MIB.'
+          item_prototypes:
+            - uuid: cc0bdcf558f344c0a5c68909f579b56d
+              name: 'Interface {#IFNAME}({#IFALIAS}): Inbound packets discarded'
+              type: DEPENDENT
+              key: 'net.if.in.discards[ifInDiscards.{#SNMPINDEX}]'
+              description: |
+                MIB: IF-MIB
+                The number of inbound packets which were chosen to be discarded
+                even though no errors had been detected to prevent their being deliverable to a higher-layer protocol.
+                One possible reason for discarding such a packet could be to free up buffer space.
+                Discontinuities in the value of this counter can occur at re-initialization of the management system,
+                and at other times as indicated by the value of ifCounterDiscontinuityTime.
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.2.2.1.13.{#SNMPINDEX}'
+                    - '0'
+                - type: CHANGE_PER_SECOND
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 3m
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+            - uuid: f12cbe9a5f3c4a8ea56dda9fb440a1e2
+              name: 'Interface {#IFNAME}({#IFALIAS}): Inbound packets with errors'
+              type: DEPENDENT
+              key: 'net.if.in.errors[ifInErrors.{#SNMPINDEX}]'
+              description: |
+                MIB: IF-MIB
+                For packet-oriented interfaces, the number of inbound packets that contained errors preventing them from being deliverable to a higher-layer protocol.  For character-oriented or fixed-length interfaces, the number of inbound transmission units that contained errors preventing them from being deliverable to a higher-layer protocol. Discontinuities in the value of this counter can occur at re-initialization of the management system, and at other times as indicated by the value of ifCounterDiscontinuityTime.
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.2.2.1.14.{#SNMPINDEX}'
+                    - '0'
+                - type: CHANGE_PER_SECOND
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 3m
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+            - uuid: e99c16e54e5d41e29de6bd323f13725e
+              name: 'Interface {#IFNAME}({#IFALIAS}): Bits received'
+              type: DEPENDENT
+              key: 'net.if.in[ifHCInOctets.{#SNMPINDEX}]'
+              units: bps
+              description: |
+                MIB: IF-MIB
+                The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets. Discontinuities in the value of this counter can occur at re-initialization of the management system, and at other times as indicated by the value of ifCounterDiscontinuityTime.
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.31.1.1.1.6.{#SNMPINDEX}'
+                    - '0'
+                - type: CHANGE_PER_SECOND
+                - type: MULTIPLIER
+                  parameters:
+                    - '8'
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+            - uuid: 956555ef3c414924ae52596f2f7097f3
+              name: 'Interface {#IFNAME}({#IFALIAS}): Outbound packets discarded'
+              type: DEPENDENT
+              key: 'net.if.out.discards[ifOutDiscards.{#SNMPINDEX}]'
+              description: |
+                MIB: IF-MIB
+                The number of outbound packets which were chosen to be discarded
+                even though no errors had been detected to prevent their being deliverable to a higher-layer protocol.
+                One possible reason for discarding such a packet could be to free up buffer space.
+                Discontinuities in the value of this counter can occur at re-initialization of the management system,
+                and at other times as indicated by the value of ifCounterDiscontinuityTime.
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.2.2.1.19.{#SNMPINDEX}'
+                    - '0'
+                - type: CHANGE_PER_SECOND
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 3m
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+            - uuid: 7c0a49bd908c49cabd497e889f8c1802
+              name: 'Interface {#IFNAME}({#IFALIAS}): Outbound packets with errors'
+              type: DEPENDENT
+              key: 'net.if.out.errors[ifOutErrors.{#SNMPINDEX}]'
+              description: |
+                MIB: IF-MIB
+                For packet-oriented interfaces, the number of outbound packets that contained errors preventing them from being deliverable to a higher-layer protocol.  For character-oriented or fixed-length interfaces, the number of outbound transmission units that contained errors preventing them from being deliverable to a higher-layer protocol. Discontinuities in the value of this counter can occur at re-initialization of the management system, and at other times as indicated by the value of ifCounterDiscontinuityTime.
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.2.2.1.20.{#SNMPINDEX}'
+                    - '0'
+                - type: CHANGE_PER_SECOND
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 3m
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+            - uuid: 8af019d7700a431c9f5e8d27e928dec4
+              name: 'Interface {#IFNAME}({#IFALIAS}): Bits sent'
+              type: DEPENDENT
+              key: 'net.if.out[ifHCOutOctets.{#SNMPINDEX}]'
+              units: bps
+              description: |
+                MIB: IF-MIB
+                The total number of octets transmitted out of the interface, including framing characters. This object is a 64-bit version of ifOutOctets.Discontinuities in the value of this counter can occur at re-initialization of the management system, and at other times as indicated by the value of ifCounterDiscontinuityTime.
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.31.1.1.1.10.{#SNMPINDEX}'
+                    - '0'
+                - type: CHANGE_PER_SECOND
+                - type: MULTIPLIER
+                  parameters:
+                    - '8'
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+            - uuid: 9f2c059c648644f28abb648c8e9e4fb5
+              name: 'Interface {#IFNAME}({#IFALIAS}): Speed'
+              type: DEPENDENT
+              key: 'net.if.speed[ifHighSpeed.{#SNMPINDEX}]'
+              trends: '0'
+              units: bps
+              description: |
+                MIB: IF-MIB
+                An estimate of the interface's current bandwidth in units of 1,000,000 bits per second. If this object reports a value of `n`, then the speed of the interface is somewhere in the range of `n-500,000` to `n+499,999`.
+                For interfaces which do not vary in bandwidth or for those where no accurate estimation can be made, this object should contain the nominal bandwidth.
+                For a sub-layer which has no concept of bandwidth, this object should be zero.
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.31.1.1.1.15.{#SNMPINDEX}'
+                    - '0'
+                - type: MULTIPLIER
+                  parameters:
+                    - '1000000'
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 1h
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+            - uuid: 523efec22cc54e23ab457581c3fd9450
+              name: 'Interface {#IFNAME}({#IFALIAS}): Operational status'
+              type: DEPENDENT
+              key: 'net.if.status[ifOperStatus.{#SNMPINDEX}]'
+              trends: '0'
+              description: |
+                MIB: IF-MIB
+                The current operational state of the interface.
+                - The testing(3) state indicates that no operational packet scan be passed
+                - If ifAdminStatus is down(2) then ifOperStatus should be down(2)
+                - If ifAdminStatus is changed to up(1) then ifOperStatus should change to up(1) if the interface is ready to transmit and receive network traffic
+                - It should change todormant(5) if the interface is waiting for external actions (such as a serial line waiting for an incoming connection)
+                - It should remain in the down(2) state if and only if there is a fault that prevents it from going to the up(1) state
+                - It should remain in the notPresent(6) state if the interface has missing(typically, hardware) components.
+              valuemap:
+                name: 'IF-MIB::ifOperStatus'
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.2.2.1.8.{#SNMPINDEX}'
+                    - '0'
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+              trigger_prototypes:
+                - uuid: d5d09ad8c8c94345a5c2a14176500372
+                  expression: '{$IFCONTROL:"{#IFNAME}"}=1 and last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])=2 and (last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#1)<>last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#2))'
+                  recovery_mode: RECOVERY_EXPRESSION
+                  recovery_expression: 'last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])<>2 or {$IFCONTROL:"{#IFNAME}"}=0'
+                  name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): Link down'
+                  opdata: 'Current state: {ITEM.LASTVALUE1}'
+                  priority: AVERAGE
+                  description: |
+                    This trigger expression works as follows:
+                    1. It can be triggered if the operations status is down.
+                    2. `{$IFCONTROL:"{#IFNAME}"}=1` - a user can redefine the context macro to "0", marking this interface as not important. No new trigger will be fired if this interface is down.
+                    3. `last(/TEMPLATE_NAME/METRIC,#1)<>last(/TEMPLATE_NAME/METRIC,#2)` - the trigger fires only if the operational status was up to (1) sometime before (so, does not fire for "eternal off" interfaces.)
+                    
+                    WARNING: if closed manually - it will not fire again on the next poll, because of .diff.
+                  manual_close: 'YES'
+                  tags:
+                    - tag: scope
+                      value: availability
+            - uuid: db90b275553b419297cd004aa3d9703b
+              name: 'Interface {#IFNAME}({#IFALIAS}): Interface type'
+              type: DEPENDENT
+              key: 'net.if.type[ifType.{#SNMPINDEX}]'
+              trends: '0'
+              description: |
+                MIB: IF-MIB
+                The type of interface.
+                Additional values for ifType are assigned by the Internet Assigned Numbers Authority (IANA),
+                through updating the syntax of the IANAifType textual convention.
+              valuemap:
+                name: 'IF-MIB::ifType'
+              preprocessing:
+                - type: SNMP_WALK_VALUE
+                  parameters:
+                    - '1.3.6.1.2.1.2.2.1.3.{#SNMPINDEX}'
+                    - '0'
+                - type: DISCARD_UNCHANGED_HEARTBEAT
+                  parameters:
+                    - 1d
+              master_item:
+                key: net.if.walk
+              tags:
+                - tag: component
+                  value: network
+                - tag: description
+                  value: '{#IFALIAS}'
+                - tag: interface
+                  value: '{#IFNAME}'
+          trigger_prototypes:
+            - uuid: 53eee46a2c474c19ba8e26569389b0fd
+              expression: |
+                change(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}])<0 and last(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}])>0
+                and (
+                last(/Huawei VRP by SNMP walk/net.if.type[ifType.{#SNMPINDEX}])=6 or
+                last(/Huawei VRP by SNMP walk/net.if.type[ifType.{#SNMPINDEX}])=7 or
+                last(/Huawei VRP by SNMP walk/net.if.type[ifType.{#SNMPINDEX}])=11 or
+                last(/Huawei VRP by SNMP walk/net.if.type[ifType.{#SNMPINDEX}])=62 or
+                last(/Huawei VRP by SNMP walk/net.if.type[ifType.{#SNMPINDEX}])=69 or
+                last(/Huawei VRP by SNMP walk/net.if.type[ifType.{#SNMPINDEX}])=117
+                )
+                and
+                (last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])<>2)
+              recovery_mode: RECOVERY_EXPRESSION
+              recovery_expression: |
+                (change(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}])>0 and last(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}],#2)>0) or
+                (last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])=2)
+              name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): Ethernet has changed to lower speed than it was before'
+              opdata: 'Current reported speed: {ITEM.LASTVALUE1}'
+              priority: INFO
+              description: 'This Ethernet connection has transitioned down from its known maximum speed. This might be a sign of autonegotiation issues. Acknowledge to close the problem manually.'
+              manual_close: 'YES'
+              dependencies:
+                - name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): Link down'
+                  expression: '{$IFCONTROL:"{#IFNAME}"}=1 and last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])=2 and (last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#1)<>last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#2))'
+                  recovery_expression: 'last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])<>2 or {$IFCONTROL:"{#IFNAME}"}=0'
+              tags:
+                - tag: scope
+                  value: performance
+            - uuid: 06a627c32901426085f8966cbbc57fb0
+              expression: |
+                (avg(/Huawei VRP by SNMP walk/net.if.in[ifHCInOctets.{#SNMPINDEX}],15m)>({$IF.UTIL.MAX:"{#IFNAME}"}/100)*last(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}]) or
+                avg(/Huawei VRP by SNMP walk/net.if.out[ifHCOutOctets.{#SNMPINDEX}],15m)>({$IF.UTIL.MAX:"{#IFNAME}"}/100)*last(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}])) and
+                last(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}])>0
+              recovery_mode: RECOVERY_EXPRESSION
+              recovery_expression: |
+                avg(/Huawei VRP by SNMP walk/net.if.in[ifHCInOctets.{#SNMPINDEX}],15m)<(({$IF.UTIL.MAX:"{#IFNAME}"}-3)/100)*last(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}]) and
+                avg(/Huawei VRP by SNMP walk/net.if.out[ifHCOutOctets.{#SNMPINDEX}],15m)<(({$IF.UTIL.MAX:"{#IFNAME}"}-3)/100)*last(/Huawei VRP by SNMP walk/net.if.speed[ifHighSpeed.{#SNMPINDEX}])
+              name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): High bandwidth usage'
+              event_name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): High bandwidth usage (>{$IF.UTIL.MAX:"{#IFNAME}"}%)'
+              opdata: 'In: {ITEM.LASTVALUE1}, out: {ITEM.LASTVALUE3}, speed: {ITEM.LASTVALUE2}'
+              priority: WARNING
+              description: 'The utilization of the network interface is close to its estimated maximum bandwidth.'
+              manual_close: 'YES'
+              dependencies:
+                - name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): Link down'
+                  expression: '{$IFCONTROL:"{#IFNAME}"}=1 and last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])=2 and (last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#1)<>last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#2))'
+                  recovery_expression: 'last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])<>2 or {$IFCONTROL:"{#IFNAME}"}=0'
+              tags:
+                - tag: scope
+                  value: performance
+            - uuid: 67d8f1081385462fa524d564e074182b
+              expression: |
+                min(/Huawei VRP by SNMP walk/net.if.in.errors[ifInErrors.{#SNMPINDEX}],5m)>{$IF.ERRORS.WARN:"{#IFNAME}"}
+                or min(/Huawei VRP by SNMP walk/net.if.out.errors[ifOutErrors.{#SNMPINDEX}],5m)>{$IF.ERRORS.WARN:"{#IFNAME}"}
+              recovery_mode: RECOVERY_EXPRESSION
+              recovery_expression: |
+                max(/Huawei VRP by SNMP walk/net.if.in.errors[ifInErrors.{#SNMPINDEX}],5m)<{$IF.ERRORS.WARN:"{#IFNAME}"}*0.8
+                and max(/Huawei VRP by SNMP walk/net.if.out.errors[ifOutErrors.{#SNMPINDEX}],5m)<{$IF.ERRORS.WARN:"{#IFNAME}"}*0.8
+              name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): High error rate'
+              event_name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): High error rate (>{$IF.ERRORS.WARN:"{#IFNAME}"} for 5m)'
+              opdata: 'errors in: {ITEM.LASTVALUE1}, errors out: {ITEM.LASTVALUE2}'
+              priority: WARNING
+              description: 'It recovers when it is below 80% of the `{$IF.ERRORS.WARN:"{#IFNAME}"}` threshold.'
+              manual_close: 'YES'
+              dependencies:
+                - name: 'Huawei VRP: Interface {#IFNAME}({#IFALIAS}): Link down'
+                  expression: '{$IFCONTROL:"{#IFNAME}"}=1 and last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])=2 and (last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#1)<>last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}],#2))'
+                  recovery_expression: 'last(/Huawei VRP by SNMP walk/net.if.status[ifOperStatus.{#SNMPINDEX}])<>2 or {$IFCONTROL:"{#IFNAME}"}=0'
+              tags:
+                - tag: scope
+                  value: availability
+                - tag: scope
+                  value: performance
+          graph_prototypes:
+            - uuid: 6c0e42e14236431a9ad5e705295e4765
+              name: 'Interface {#IFNAME}({#IFALIAS}): Network traffic'
+              graph_items:
+                - drawtype: GRADIENT_LINE
+                  color: 199C0D
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'net.if.in[ifHCInOctets.{#SNMPINDEX}]'
+                - sortorder: '1'
+                  drawtype: BOLD_LINE
+                  color: F63100
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'net.if.out[ifHCOutOctets.{#SNMPINDEX}]'
+                - sortorder: '2'
+                  color: 00611C
+                  yaxisside: RIGHT
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'net.if.out.errors[ifOutErrors.{#SNMPINDEX}]'
+                - sortorder: '3'
+                  color: F7941D
+                  yaxisside: RIGHT
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'net.if.in.errors[ifInErrors.{#SNMPINDEX}]'
+                - sortorder: '4'
+                  color: FC6EA3
+                  yaxisside: RIGHT
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'net.if.out.discards[ifOutDiscards.{#SNMPINDEX}]'
+                - sortorder: '5'
+                  color: 6C59DC
+                  yaxisside: RIGHT
+                  item:
+                    host: 'Huawei VRP by SNMP walk'
+                    key: 'net.if.in.discards[ifInDiscards.{#SNMPINDEX}]'
+          master_item:
+            key: net.if.walk
+          preprocessing:
+            - type: SNMP_WALK_TO_JSON
+              parameters:
+                - '{#IFOPERSTATUS}'
+                - 1.3.6.1.2.1.2.2.1.8
+                - '0'
+                - '{#IFADMINSTATUS}'
+                - 1.3.6.1.2.1.2.2.1.7
+                - '0'
+                - '{#IFALIAS}'
+                - 1.3.6.1.2.1.31.1.1.1.18
+                - '0'
+                - '{#IFNAME}'
+                - 1.3.6.1.2.1.31.1.1.1.1
+                - '0'
+                - '{#IFDESCR}'
+                - 1.3.6.1.2.1.2.2.1.2
+                - '0'
+                - '{#IFTYPE}'
+                - 1.3.6.1.2.1.2.2.1.3
+                - '0'
+            - type: DISCARD_UNCHANGED_HEARTBEAT
+              parameters:
+                - 1h
+      tags:
+        - tag: class
+          value: network
+        - tag: target
+          value: huawei
+        - tag: target
+          value: huawei-vrp
+      macros:
+        - macro: '{$CPU.UTIL.CRIT}'
+          value: '90'
+        - macro: '{$FAN_CRIT_STATUS}'
+          value: '2'
+        - macro: '{$ICMP_LOSS_WARN}'
+          value: '20'
+          description: 'Warning threshold of ICMP packet loss in %.'
+          config:
+            type: TEXT
+            priority: '8'
+            section_name: Thresholds
+            label: 'Threshold of ICMP packet loss'
+            description: 'Warning threshold of ICMP packet loss in %. In the range from 0 to 100 inclusive.'
+            regex: '^-?([0-9]+|(([0-9]+)\.([0-9]+)))$'
+        - macro: '{$ICMP_RESPONSE_TIME_WARN}'
+          value: '0.15'
+          description: 'Warning threshold of the average ICMP response time in seconds.'
+          config:
+            type: TEXT
+            priority: '9'
+            section_name: Thresholds
+            label: 'Threshold of the average ICMP response'
+            description: 'Warning threshold of the average ICMP response time in seconds. No less than 0.'
+            regex: '^-?([0-9]+|(([0-9]+)\.([0-9]+)))$'
+        - macro: '{$IF.ERRORS.WARN}'
+          value: '2'
+          description: 'Warning threshold of error packet rate. Can be used with interface name as context.'
+        - macro: '{$IF.UTIL.MAX}'
+          value: '90'
+        - macro: '{$IFCONTROL}'
+          value: '1'
+        - macro: '{$MEMORY.UTIL.MAX}'
+          value: '90'
+        - macro: '{$NET.IF.IFADMINSTATUS.MATCHES}'
+          value: '^.*'
+        - macro: '{$NET.IF.IFADMINSTATUS.NOT_MATCHES}'
+          value: ^2$
+          description: 'Ignore down(2) administrative status'
+        - macro: '{$NET.IF.IFALIAS.MATCHES}'
+          value: '.*'
+        - macro: '{$NET.IF.IFALIAS.NOT_MATCHES}'
+          value: CHANGE_IF_NEEDED
+        - macro: '{$NET.IF.IFDESCR.MATCHES}'
+          value: '.*'
+        - macro: '{$NET.IF.IFDESCR.NOT_MATCHES}'
+          value: CHANGE_IF_NEEDED
+        - macro: '{$NET.IF.IFNAME.MATCHES}'
+          value: '^.*$'
+        - macro: '{$NET.IF.IFNAME.NOT_MATCHES}'
+          value: '(^Software Loopback Interface|^NULL[0-9.]*$|^[Ll]o[0-9.]*$|^[Ss]ystem$|^Nu[0-9.]*$|^veth[0-9a-z]+$|docker[0-9]+|br-[a-z0-9]{12})'
+          description: 'Filter out loopbacks, nulls, docker veth links and docker0 bridge by default'
+        - macro: '{$NET.IF.IFOPERSTATUS.MATCHES}'
+          value: '^.*$'
+        - macro: '{$NET.IF.IFOPERSTATUS.NOT_MATCHES}'
+          value: ^6$
+          description: 'Ignore notPresent(6)'
+        - macro: '{$NET.IF.IFTYPE.MATCHES}'
+          value: '.*'
+        - macro: '{$NET.IF.IFTYPE.NOT_MATCHES}'
+          value: CHANGE_IF_NEEDED
+        - macro: '{$SNMP.TIMEOUT}'
+          value: 5m
+          description: 'Time interval for the SNMP availability trigger.'
+          config:
+            type: TEXT
+            priority: '7'
+            section_name: Other
+            label: 'Time interval'
+            description: 'Time interval for the SNMP availability trigger.'
+        - macro: '{$TEMP_CRIT}'
+          value: '60'
+        - macro: '{$TEMP_CRIT_LOW}'
+          value: '5'
+        - macro: '{$TEMP_WARN}'
+          value: '50'
+      dashboards:
+        - uuid: 8c1df762e31f4a96b284f7a1589e6ea9
+          name: 'Network interfaces'
+          pages:
+            - widgets:
+                - type: graphprototype
+                  width: '72'
+                  height: '5'
+                  fields:
+                    - type: INTEGER
+                      name: columns
+                      value: '1'
+                    - type: GRAPH_PROTOTYPE
+                      name: graphid.0
+                      value:
+                        host: 'Huawei VRP by SNMP walk'
+                        name: 'Interface {#IFNAME}({#IFALIAS}): Network traffic'
+                    - type: STRING
+                      name: reference
+                      value: AAAAA
+      valuemaps:
+          name: 'EtherLike-MIB::dot3StatsDuplexStatus'
+          mappings:
+            - value: '1'
+              newvalue: unknown
+            - value: '2'
+              newvalue: halfDuplex
+            - value: '3'
+              newvalue: fullDuplex
+        - uuid: e13962c1f7db4f25b5bd3bdbc90cdcb5
+          name: 'HUAWEI-ENTITY-EXTENT-MIB::hwEntityFanState'
+          mappings:
+            - value: '1'
+              newvalue: normal
+            - value: '2'
+              newvalue: abnormal
+        - uuid: aa7726f326874651b16d3f4454407006
+          name: 'IF-MIB::ifOperStatus'
+          mappings:
+            - value: '1'
+              newvalue: up
+            - value: '2'
+              newvalue: down
+            - value: '4'
+              newvalue: unknown
+            - value: '5'
+              newvalue: dormant
+            - value: '6'
+              newvalue: notPresent
+            - value: '7'
+              newvalue: lowerLayerDown
+        - uuid: 7ae6c7d362f544a596cc3826463012ef
+          name: 'IF-MIB::ifType'
+          mappings:
+            - value: '1'
+              newvalue: other
+            - value: '2'
+              newvalue: regular1822
+            - value: '3'
+              newvalue: hdh1822
+            - value: '4'
+              newvalue: ddnX25
+            - value: '5'
+              newvalue: rfc877x25
+            - value: '6'
+              newvalue: ethernetCsmacd
+            - value: '7'
+              newvalue: iso88023Csmacd
+            - value: '8'
+              newvalue: iso88024TokenBus
+            - value: '9'
+              newvalue: iso88025TokenRing
+            - value: '10'
+              newvalue: iso88026Man
+            - value: '11'
+              newvalue: starLan
+            - value: '12'
+              newvalue: proteon10Mbit
+            - value: '13'
+              newvalue: proteon80Mbit
+            - value: '14'
+              newvalue: hyperchannel
+            - value: '15'
+              newvalue: fddi
+            - value: '16'
+              newvalue: lapb
+            - value: '17'
+              newvalue: sdlc
+            - value: '18'
+              newvalue: ds1
+            - value: '19'
+              newvalue: e1
+            - value: '20'
+              newvalue: basicISDN
+            - value: '21'
+              newvalue: primaryISDN
+            - value: '22'
+              newvalue: propPointToPointSerial
+            - value: '23'
+              newvalue: ppp
+            - value: '24'
+              newvalue: softwareLoopback
+            - value: '25'
+              newvalue: eon
+            - value: '26'
+              newvalue: ethernet3Mbit
+            - value: '27'
+              newvalue: nsip
+            - value: '28'
+              newvalue: slip
+            - value: '29'
+              newvalue: ultra
+            - value: '30'
+              newvalue: ds3
+            - value: '31'
+              newvalue: sip
+            - value: '32'
+              newvalue: frameRelay
+            - value: '33'
+              newvalue: rs232
+            - value: '34'
+              newvalue: para
+            - value: '35'
+              newvalue: arcnet
+            - value: '36'
+              newvalue: arcnetPlus
+            - value: '37'
+              newvalue: atm
+            - value: '38'
+              newvalue: miox25
+            - value: '39'
+              newvalue: sonet
+            - value: '40'
+              newvalue: x25ple
+            - value: '41'
+              newvalue: iso88022llc
+            - value: '42'
+              newvalue: localTalk
+            - value: '43'
+              newvalue: smdsDxi
+            - value: '44'
+              newvalue: frameRelayService
+            - value: '45'
+              newvalue: v35
+            - value: '46'
+              newvalue: hssi
+            - value: '47'
+              newvalue: hippi
+            - value: '48'
+              newvalue: modem
+            - value: '49'
+              newvalue: aal5
+            - value: '50'
+              newvalue: sonetPath
+            - value: '51'
+              newvalue: sonetVT
+            - value: '52'
+              newvalue: smdsIcip
+            - value: '53'
+              newvalue: propVirtual
+            - value: '54'
+              newvalue: propMultiplexor
+            - value: '55'
+              newvalue: ieee80212
+            - value: '56'
+              newvalue: fibreChannel
+            - value: '57'
+              newvalue: hippiInterface
+            - value: '58'
+              newvalue: frameRelayInterconnect
+            - value: '59'
+              newvalue: aflane8023
+            - value: '60'
+              newvalue: aflane8025
+            - value: '61'
+              newvalue: cctEmul
+            - value: '62'
+              newvalue: fastEther
+            - value: '63'
+              newvalue: isdn
+            - value: '64'
+              newvalue: v11
+            - value: '65'
+              newvalue: v36
+            - value: '66'
+              newvalue: g703at64k
+            - value: '67'
+              newvalue: g703at2mb
+            - value: '68'
+              newvalue: qllc
+            - value: '69'
+              newvalue: fastEtherFX
+            - value: '70'
+              newvalue: channel
+            - value: '71'
+              newvalue: ieee80211
+            - value: '72'
+              newvalue: ibm370parChan
+            - value: '73'
+              newvalue: escon
+            - value: '74'
+              newvalue: dlsw
+            - value: '75'
+              newvalue: isdns
+            - value: '76'
+              newvalue: isdnu
+            - value: '77'
+              newvalue: lapd
+            - value: '78'
+              newvalue: ipSwitch
+            - value: '79'
+              newvalue: rsrb
+            - value: '80'
+              newvalue: atmLogical
+            - value: '81'
+              newvalue: ds0
+            - value: '82'
+              newvalue: ds0Bundle
+            - value: '83'
+              newvalue: bsc
+            - value: '84'
+              newvalue: async
+            - value: '85'
+              newvalue: cnr
+            - value: '86'
+              newvalue: iso88025Dtr
+            - value: '87'
+              newvalue: eplrs
+            - value: '88'
+              newvalue: arap
+            - value: '89'
+              newvalue: propCnls
+            - value: '90'
+              newvalue: hostPad
+            - value: '91'
+              newvalue: termPad
+            - value: '92'
+              newvalue: frameRelayMPI
+            - value: '93'
+              newvalue: x213
+            - value: '94'
+              newvalue: adsl
+            - value: '95'
+              newvalue: radsl
+            - value: '96'
+              newvalue: sdsl
+            - value: '97'
+              newvalue: vdsl
+            - value: '98'
+              newvalue: iso88025CRFPInt
+            - value: '99'
+              newvalue: myrinet
+            - value: '100'
+              newvalue: voiceEM
+            - value: '101'
+              newvalue: voiceFXO
+            - value: '102'
+              newvalue: voiceFXS
+            - value: '103'
+              newvalue: voiceEncap
+            - value: '104'
+              newvalue: voiceOverIp
+            - value: '105'
+              newvalue: atmDxi
+            - value: '106'
+              newvalue: atmFuni
+            - value: '107'
+              newvalue: atmIma
+            - value: '108'
+              newvalue: pppMultilinkBundle
+            - value: '109'
+              newvalue: ipOverCdlc
+            - value: '110'
+              newvalue: ipOverClaw
+            - value: '111'
+              newvalue: stackToStack
+            - value: '112'
+              newvalue: virtualIpAddress
+            - value: '113'
+              newvalue: mpc
+            - value: '114'
+              newvalue: ipOverAtm
+            - value: '115'
+              newvalue: iso88025Fiber
+            - value: '116'
+              newvalue: tdlc
+            - value: '117'
+              newvalue: gigabitEthernet
+            - value: '118'
+              newvalue: hdlc
+            - value: '119'
+              newvalue: lapf
+            - value: '120'
+              newvalue: v37
+            - value: '121'
+              newvalue: x25mlp
+            - value: '122'
+              newvalue: x25huntGroup
+            - value: '123'
+              newvalue: trasnpHdlc
+            - value: '124'
+              newvalue: interleave
+            - value: '125'
+              newvalue: fast
+            - value: '126'
+              newvalue: ip
+            - value: '127'
+              newvalue: docsCableMaclayer
+            - value: '128'
+              newvalue: docsCableDownstream
+            - value: '129'
+              newvalue: docsCableUpstream
+            - value: '130'
+              newvalue: a12MppSwitch
+            - value: '131'
+              newvalue: tunnel
+            - value: '132'
+              newvalue: coffee
+            - value: '133'
+              newvalue: ces
+            - value: '134'
+              newvalue: atmSubInterface
+            - value: '135'
+              newvalue: l2vlan
+            - value: '136'
+              newvalue: l3ipvlan
+            - value: '137'
+              newvalue: l3ipxvlan
+            - value: '138'
+              newvalue: digitalPowerline
+            - value: '139'
+              newvalue: mediaMailOverIp
+            - value: '140'
+              newvalue: dtm
+            - value: '141'
+              newvalue: dcn
+            - value: '142'
+              newvalue: ipForward
+            - value: '143'
+              newvalue: msdsl
+            - value: '144'
+              newvalue: ieee1394
+            - value: '145'
+              newvalue: if-gsn
+            - value: '146'
+              newvalue: dvbRccMacLayer
+            - value: '147'
+              newvalue: dvbRccDownstream
+            - value: '148'
+              newvalue: dvbRccUpstream
+            - value: '149'
+              newvalue: atmVirtual
+            - value: '150'
+              newvalue: mplsTunnel
+            - value: '151'
+              newvalue: srp
+            - value: '152'
+              newvalue: voiceOverAtm
+            - value: '153'
+              newvalue: voiceOverFrameRelay
+            - value: '154'
+              newvalue: idsl
+            - value: '155'
+              newvalue: compositeLink
+            - value: '156'
+              newvalue: ss7SigLink
+            - value: '157'
+              newvalue: propWirelessP2P
+            - value: '158'
+              newvalue: frForward
+            - value: '159'
+              newvalue: rfc1483
+            - value: '160'
+              newvalue: usb
+            - value: '161'
+              newvalue: ieee8023adLag
+            - value: '162'
+              newvalue: bgppolicyaccounting
+            - value: '163'
+              newvalue: frf16MfrBundle
+            - value: '164'
+              newvalue: h323Gatekeeper
+            - value: '165'
+              newvalue: h323Proxy
+            - value: '166'
+              newvalue: mpls
+            - value: '167'
+              newvalue: mfSigLink
+            - value: '168'
+              newvalue: hdsl2
+            - value: '169'
+              newvalue: shdsl
+            - value: '170'
+              newvalue: ds1FDL
+            - value: '171'
+              newvalue: pos
+            - value: '172'
+              newvalue: dvbAsiIn
+            - value: '173'
+              newvalue: dvbAsiOut
+            - value: '174'
+              newvalue: plc
+            - value: '175'
+              newvalue: nfas
+            - value: '176'
+              newvalue: tr008
+            - value: '177'
+              newvalue: gr303RDT
+            - value: '178'
+              newvalue: gr303IDT
+            - value: '179'
+              newvalue: isup
+            - value: '180'
+              newvalue: propDocsWirelessMaclayer
+            - value: '181'
+              newvalue: propDocsWirelessDownstream
+            - value: '182'
+              newvalue: propDocsWirelessUpstream
+            - value: '183'
+              newvalue: hiperlan2
+            - value: '184'
+              newvalue: propBWAp2Mp
+            - value: '185'
+              newvalue: sonetOverheadChannel
+            - value: '186'
+              newvalue: digitalWrapperOverheadChannel
+            - value: '187'
+              newvalue: aal2
+            - value: '188'
+              newvalue: radioMAC
+            - value: '189'
+              newvalue: atmRadio
+            - value: '190'
+              newvalue: imt
+            - value: '191'
+              newvalue: mvl
+            - value: '192'
+              newvalue: reachDSL
+            - value: '193'
+              newvalue: frDlciEndPt
+            - value: '194'
+              newvalue: atmVciEndPt
+            - value: '195'
+              newvalue: opticalChannel
+            - value: '196'
+              newvalue: opticalTransport
+            - value: '197'
+              newvalue: propAtm
+            - value: '198'
+              newvalue: voiceOverCable
+            - value: '199'
+              newvalue: infiniband
+            - value: '200'
+              newvalue: teLink
+            - value: '201'
+              newvalue: q2931
+            - value: '202'
+              newvalue: virtualTg
+            - value: '203'
+              newvalue: sipTg
+            - value: '204'
+              newvalue: sipSig
+            - value: '205'
+              newvalue: docsCableUpstreamChannel
+            - value: '206'
+              newvalue: econet
+            - value: '207'
+              newvalue: pon155
+            - value: '208'
+              newvalue: pon622
+            - value: '209'
+              newvalue: bridge
+            - value: '210'
+              newvalue: linegroup
+            - value: '211'
+              newvalue: voiceEMFGD
+            - value: '212'
+              newvalue: voiceFGDEANA
+            - value: '213'
+              newvalue: voiceDID
+            - value: '214'
+              newvalue: mpegTransport
+            - value: '215'
+              newvalue: sixToFour
+            - value: '216'
+              newvalue: gtp
+            - value: '217'
+              newvalue: pdnEtherLoop1
+            - value: '218'
+              newvalue: pdnEtherLoop2
+            - value: '219'
+              newvalue: opticalChannelGroup
+            - value: '220'
+              newvalue: homepna
+            - value: '221'
+              newvalue: gfp
+            - value: '222'
+              newvalue: ciscoISLvlan
+            - value: '223'
+              newvalue: actelisMetaLOOP
+            - value: '224'
+              newvalue: fcipLink
+            - value: '225'
+              newvalue: rpr
+            - value: '226'
+              newvalue: qam
+            - value: '227'
+              newvalue: lmp
+            - value: '228'
+              newvalue: cblVectaStar
+            - value: '229'
+              newvalue: docsCableMCmtsDownstream
+            - value: '230'
+              newvalue: adsl2
+            - value: '231'
+              newvalue: macSecControlledIF
+            - value: '232'
+              newvalue: macSecUncontrolledIF
+            - value: '233'
+              newvalue: aviciOpticalEther
+            - value: '234'
+              newvalue: atmbond
+            - value: '235'
+              newvalue: voiceFGDOS
+            - value: '236'
+              newvalue: mocaVersion1
+            - value: '237'
+              newvalue: ieee80216WMAN
+            - value: '238'
+              newvalue: adsl2plus
+            - value: '239'
+              newvalue: dvbRcsMacLayer
+            - value: '240'
+              newvalue: dvbTdm
+            - value: '241'
+              newvalue: dvbRcsTdma
+            - value: '242'
+              newvalue: x86Laps
+            - value: '243'
+              newvalue: wwanPP
+            - value: '244'
+              newvalue: wwanPP2
+            - value: '245'
+              newvalue: voiceEBS
+            - value: '246'
+              newvalue: ifPwType
+            - value: '247'
+              newvalue: ilan
+            - value: '248'
+              newvalue: pip
+            - value: '249'
+              newvalue: aluELP
+            - value: '250'
+              newvalue: gpon
+            - value: '251'
+              newvalue: vdsl2
+            - value: '252'
+              newvalue: capwapDot11Profile
+            - value: '253'
+              newvalue: capwapDot11Bss
+            - value: '254'
+              newvalue: capwapWtpVirtualRadio
+            - value: '255'
+              newvalue: bits
+            - value: '256'
+              newvalue: docsCableUpstreamRfPort
+            - value: '257'
+              newvalue: cableDownstreamRfPort
+            - value: '258'
+              newvalue: vmwareVirtualNic
+            - value: '259'
+              newvalue: ieee802154
+            - value: '260'
+              newvalue: otnOdu
+            - value: '261'
+              newvalue: otnOtu
+            - value: '262'
+              newvalue: ifVfiType
+            - value: '263'
+              newvalue: g9981
+            - value: '264'
+              newvalue: g9982
+            - value: '265'
+              newvalue: g9983
+            - value: '266'
+              newvalue: aluEpon
+            - value: '267'
+              newvalue: aluEponOnu
+            - value: '268'
+              newvalue: aluEponPhysicalUni
+            - value: '269'
+              newvalue: aluEponLogicalLink
+            - value: '270'
+              newvalue: aluGponOnu
+            - value: '271'
+              newvalue: aluGponPhysicalUni
+            - value: '272'
+              newvalue: vmwareNicTeam
+            - value: '277'
+              newvalue: docsOfdmDownstream
+            - value: '278'
+              newvalue: docsOfdmaUpstream
+            - value: '279'
+              newvalue: gfast
+            - value: '280'
+              newvalue: sdci
+            - value: '281'
+              newvalue: xboxWireless
+            - value: '282'
+              newvalue: fastdsl
+            - value: '283'
+              newvalue: docsCableScte55d1FwdOob
+            - value: '284'
+              newvalue: docsCableScte55d1RetOob
+            - value: '285'
+              newvalue: docsCableScte55d2DsOob
+            - value: '286'
+              newvalue: docsCableScte55d2UsOob
+            - value: '287'
+              newvalue: docsCableNdf
+            - value: '288'
+              newvalue: docsCableNdr
+            - value: '289'
+              newvalue: ptm
+            - value: '290'
+              newvalue: ghn
+        - uuid: 59dccab0fcbf4da189c43f4e159efa92
+          name: 'Service state'
+          mappings:
+            - value: '0'
+              newvalue: Down
+            - value: '1'
+              newvalue: Up
+        - uuid: 8a9bae9b27f0412394f34cc5de59ca69
+          name: zabbix.host.available
+          mappings:
+            - value: '0'
+              newvalue: 'not available'
+            - value: '1'
+              newvalue: available
+            - value: '2'
+              newvalue: unknown
+  triggers:
+    - uuid: df3496055af942dcbca475a24b02fddf
+      expression: '(last(/Huawei VRP by SNMP walk/system.hw.uptime[hrSystemUptime.0])>0 and last(/Huawei VRP by SNMP walk/system.hw.uptime[hrSystemUptime.0])<10m) or (last(/Huawei VRP by SNMP walk/system.hw.uptime[hrSystemUptime.0])=0 and last(/Huawei VRP by SNMP walk/system.net.uptime[sysUpTime.0])<10m)'
+      name: 'Huawei VRP: Host has been restarted'
+      event_name: 'Huawei VRP: {HOST.NAME} has been restarted (uptime < 10m)'
+      priority: WARNING
+      description: 'Uptime is less than 10 minutes.'
+      manual_close: 'YES'
+      dependencies:
+        - name: 'Huawei VRP: No SNMP data collection'
+          expression: 'max(/Huawei VRP by SNMP walk/zabbix[host,snmp,available],{$SNMP.TIMEOUT})=0'
+      tags:
+        - tag: scope
+          value: notice

+ 0 - 12
web-modules/WecomCenter/templates/demo.yaml

@@ -1,12 +0,0 @@
-zabbix_export:
-  version: '7.0'
-  template_groups:
-    - uuid: 7df96b18c230490a9a0a9e2307226338
-      name: Templates
-  templates:
-    - uuid: a571c0d144b14fd4a87a9d9b2aa9fcd6
-      template: 'Demo - WeCom Center'
-      name: 'Demo - WeCom Center'
-      description: 'Sample template shipped with the WeCom Center module to demonstrate one-click template import.'
-      groups:
-        - name: Templates

+ 193 - 190
web-modules/WecomCenter/views/wecom.center.view.php

@@ -1,6 +1,7 @@
 <?php declare(strict_types = 0);
 /*
 ** WeCom Center - page view (three tabs: Alert / Optimization / Maintenance).
+** Rendered as clean card HTML on top of Zabbix's page chrome.
 ** @var CView $this
 ** @var array  $data
 */
@@ -9,15 +10,18 @@ use Modules\WecomCenter\Lib\I18n;
 
 $this->addCssFile('modules/WecomCenter/assets/wecom.center.css');
 
-$save_url = (new CUrl('zabbix.php'))->setArgument('action', 'wecom.center.save')->getUrl();
+$e = function ($v) { return htmlspecialchars((string) ($v ?? ''), ENT_QUOTES, 'UTF-8'); };
+$t = function (string $k, array $a = []) use ($e) { return $e(I18n::t($k, $a)); };
+
+$save = $e((new CUrl('zabbix.php'))->setArgument('action', 'wecom.center.save')->getUrl());
 $view_url = (new CUrl('zabbix.php'))->setArgument('action', 'wecom.center.view')->getUrl();
+$mtid = $e($data['mediatypeid']);
 
 $html_page = (new CHtmlPage())->setTitle(I18n::t('page.title'));
 
 if (!$data['mediatype']) {
-	$html_page->addItem((new CDiv())->addItem(
-		(new CTag('p'))->addItem(I18n::t('msg.no_mediatype'))
-	));
+	$html_page->addItem('<div class="wc-wrap"><div class="wc-card"><div class="wc-card__body">'
+		.$t('msg.no_mediatype').'</div></div></div>');
 	$html_page->show();
 	return;
 }
@@ -25,234 +29,233 @@ if (!$data['mediatype']) {
 $mask = (int) $data['severity'];
 $enabled = ((int) $data['active'] === 0);
 
-$tabs = new CTabView();
+/* helper to build a card */
+$card = function (string $ico, string $title, string $body, string $extra = '', string $sub = '') {
+	return '<div class="wc-card'.$extra.'"><div class="wc-card__head"><span class="wc-card__ico">'.$ico.'</span>'
+		.'<span class="wc-card__title">'.$title.'</span>'
+		.($sub !== '' ? '<span class="wc-card__sub">'.$sub.'</span>' : '')
+		.'</div><div class="wc-card__body">'.$body.'</div></div>';
+};
 
-/* ================================================================== */
-/*  TAB 1 - ALERT (robot + strategy engine + manual threshold)        */
-/* ================================================================== */
-$alert = new CDiv();
+/* ============================ TAB 1: ALERT ============================ */
 
-// --- 1a. Robot key -----------------------------------------------------
-$robot_form = (new CForm())
-	->addItem((new CVar('mediatypeid', $data['mediatypeid']))->removeId())
-	->addItem(
-		(new CFormList())->addRow(I18n::t('lbl.key'),
-			(new CTextBox('webhook_url', $data['webhook_url']))
-				->setWidth(ZBX_TEXTAREA_BIG_WIDTH)
-				->setAttribute('style', 'font-family:monospace;')
-		)
-	)
-	->addItem(
-		(new CDiv())
-			->addItem((new CSubmitButton(I18n::t('btn.save'), 'op', 'save_robot')))
-			->addItem((new CSubmitButton(I18n::t('btn.test'), 'op', 'test_robot'))->addClass(ZBX_STYLE_BTN_ALT))
-	)
-	->setAction($save_url)
-	->setId('wc-robot');
+// -- robot --
+$robotBody =
+	'<form method="post" action="'.$save.'">'
+	.'<input type="hidden" name="mediatypeid" value="'.$mtid.'">'
+	.'<div class="wc-field"><label>'.$t('lbl.key').'</label>'
+	.'<input class="wc-input wc-input--mono" type="text" name="webhook_url" value="'.$e($data['webhook_url']).'"></div>'
+	.'<div class="wc-actions">'
+	.'<button class="wc-btn wc-btn--primary" type="submit" name="op" value="save_robot">'.$t('btn.save').'</button>'
+	.'<button class="wc-btn wc-btn--ghost" type="submit" name="op" value="test_robot">'.$t('btn.test').'</button>'
+	.'</div></form>';
+$robotCard = $card('&#129302;', $t('sec.robot'), $robotBody, '', $e($data['mediatype']['name'] ?? ''));
 
-$alert->addItem((new CTag('h4'))->addItem(I18n::t('sec.robot')));
-$alert->addItem($robot_form);
+// -- threshold --
+$sevChecks = '';
+for ($i = 1; $i <= 6; $i++) {
+	$bit = 1 << ($i - 1);
+	$chk = (($mask & $bit) !== 0) ? ' checked' : '';
+	$sevChecks .= '<label class="wc-checkrow"><input type="checkbox" name="sev_'.$i.'"'.$chk.'> '
+		.'<span class="wc-sev wc-sev-'.$i.'">'.$t('sev.'.$i).'</span></label>';
+}
+$thresholdBody =
+	'<div class="wc-hint">'.$t('lbl.threshold_hint').'</div>'
+	.'<form method="post" action="'.$save.'">'
+	.'<input type="hidden" name="mediatypeid" value="'.$mtid.'">'
+	.'<div class="wc-field"><label class="wc-checkrow"><input type="checkbox" name="enabled"'.($enabled ? ' checked' : '').'> '.$t('lbl.alerting_on').'</label></div>'
+	.'<div class="wc-field"><label>'.$t('lbl.severity').'</label><div class="wc-checks">'.$sevChecks.'</div></div>'
+	.'<div class="wc-actions"><button class="wc-btn wc-btn--primary" type="submit" name="op" value="save_alert">'.$t('btn.save').'</button></div>'
+	.'</form>';
+$thresholdCard = $card('&#9881;&#65039;', $t('sec.threshold'), $thresholdBody);
 
-// --- 1b. Strategy presets ---------------------------------------------
-$preset_tbl = new CTable();
-$preset_tbl->setHeader([I18n::t('preset.col.name'), I18n::t('preset.col.desc'), I18n::t('preset.col.action')]);
+// -- strategy presets --
+$presetRows = '';
 foreach ($data['presets'] as $key => $p) {
 	$is_cur = ((string) $data['current_strategy'] === (string) $key);
-	$name_cell = new CDiv();
-	$name_cell->addItem(I18n::t($p['label']));
-	if ($is_cur) {
-		$name_cell->addItem((new CSpan(I18n::t('preset.current')))->addClass(ZBX_STYLE_GREEN));
-	}
-	$preview_link = new CLink(I18n::t('btn.preview'),
-		(new CUrl('zabbix.php'))
-			->setArgument('action', 'wecom.center.view')
-			->setArgument('mediatypeid', $data['mediatypeid'])
-			->setArgument('preview_preset', $key)
-			->getUrl()
-	);
-	$apply_btn = (new CSubmitButton(I18n::t('btn.apply'), 'apply_strategy', $key))
-		->addClass(ZBX_STYLE_BTN_ALT);
-	$preset_tbl->addRow([
-		$name_cell,
-		I18n::t($p['desc']),
-		(new CDiv())->addItem($preview_link)->addItem($apply_btn)
-	]);
+	$name = $t($p['label']).($is_cur ? ' <span class="wc-pill wc-pill--cur">'.$t('preset.current').'</span>' : '');
+	$prevUrl = $e((new CUrl('zabbix.php'))
+		->setArgument('action', 'wecom.center.view')
+		->setArgument('mediatypeid', $data['mediatypeid'])
+		->setArgument('preview_preset', $key)
+		->getUrl());
+	$presetRows .=
+		'<div class="wc-preset">'
+		.'<div class="wc-preset__main"><div class="wc-preset__name">'.$name.'</div>'
+		.'<div class="wc-preset__desc">'.$t($p['desc']).'</div></div>'
+		.'<div class="wc-preset__act">'
+		.'<a class="wc-btn wc-btn--ghost wc-btn--sm" href="'.$prevUrl.'">'.$t('btn.preview').'</a>'
+		.'<form method="post" action="'.$save.'" style="margin:0"><input type="hidden" name="mediatypeid" value="'.$mtid.'">'
+		.'<button class="wc-btn wc-btn--primary wc-btn--sm" type="submit" name="apply_strategy" value="'.$e($key).'">'.$t('btn.apply').'</button></form>'
+		.'</div></div>';
 }
-$strategy_form = (new CForm())
-	->addItem((new CVar('mediatypeid', $data['mediatypeid']))->removeId())
-	->addItem(new CDiv($preset_tbl))
-	->setAction($save_url)
-	->setId('wc-strategy');
+$strategyBody = '<div class="wc-hint">'.$t('lbl.strategy_hint').'</div>'.$presetRows;
+$strategyCard = $card('&#128680;', $t('sec.strategy'), $strategyBody, ' wc-card--wide');
 
-$alert->addItem((new CTag('h4'))->addItem(I18n::t('sec.strategy')));
-$alert->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('lbl.strategy_hint')));
-$alert->addItem($strategy_form);
-
-// --- 1c. Preview result (dry-run) -------------------------------------
+// -- preview --
+$previewCard = '';
 if ($data['preview'] !== null) {
 	$pv = $data['preview'];
 	$pkey = $data['preview_key'];
-	$pt = new CTable();
-	$pt->setHeader([
-		I18n::t('cls.col.class'), I18n::t('cls.col.target'),
-		I18n::t('cls.col.count'), I18n::t('cls.col.changes')
-	]);
+	$rows = '';
 	foreach ($pv['classes'] as $ck => $c) {
-		$label = I18n::t($data['classes'][$ck]['label'] ?? $ck);
-		$pt->addRow([$label, I18n::t('sev.'.($c['target'] + 1)), $c['count'], $c['changes']]);
+		$label = $t($data['classes'][$ck]['label'] ?? $ck);
+		$rows .= '<tr><td>'.$label.'</td><td><span class="wc-sev wc-sev-'.((int) $c['target'] + 1).'">'.$t('sev.'.($c['target'] + 1)).'</span></td>'
+			.'<td class="num">'.$e($c['count']).'</td><td class="num">'.$e($c['changes']).'</td></tr>';
 	}
-	$pt->addRow([(new CTag('b'))->addItem(I18n::t('cls.total')), '', (new CTag('b'))->addItem((string) $pv['total']), (new CTag('b'))->addItem((string) $pv['changes'])]);
-	$alert->addItem(
-		(new CDiv())
-			->addItem((new CTag('h4'))->addItem(
-				I18n::t('preview.title', [I18n::t($data['presets'][$pkey]['label'] ?? $pkey)])
-			))
-			->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('preview.hint')))
-			->addItem($pt)
-	);
-}
-
-// --- 1d. Manual threshold override ------------------------------------
-$sev_items = new CList();
-for ($i = 1; $i <= 6; $i++) {
-	$bit = 1 << ($i - 1);
-	$sev_items->addItem(
-		(new CCheckBox('sev_'.$i))->setLabel(I18n::t('sev.'.$i))->setChecked(($mask & $bit) !== 0)
-	);
+	$rows .= '<tr class="wc-tr-total"><td>'.$t('cls.total').'</td><td></td>'
+		.'<td class="num">'.$e($pv['total']).'</td><td class="num">'.$e($pv['changes']).'</td></tr>';
+	$tbl = '<table class="wc-table"><thead><tr><th>'.$t('cls.col.class').'</th><th>'.$t('cls.col.target').'</th>'
+		.'<th class="num">'.$t('cls.col.count').'</th><th class="num">'.$t('cls.col.changes').'</th></tr></thead><tbody>'.$rows.'</tbody></table>';
+	$body = '<div class="wc-hint">'.$t('preview.hint').'</div>'.$tbl;
+	$previewCard = $card('&#128269;', $t('preview.title', [I18n::t($data['presets'][$pkey]['label'] ?? $pkey)]), $body, ' wc-card--wide');
 }
-$sev_form = (new CForm())
-	->addItem((new CVar('mediatypeid', $data['mediatypeid']))->removeId())
-	->addItem(
-		(new CFormList())
-			->addRow(I18n::t('lbl.alerting_on'),
-				(new CCheckBox('enabled'))->setLabel(I18n::t('lbl.alerting_on'))->setChecked($enabled))
-			->addRow(I18n::t('lbl.severity'), $sev_items)
-	)
-	->addItem((new CSubmitButton(I18n::t('btn.save'), 'op', 'save_alert')))
-	->setAction($save_url)
-	->setId('wc-sev');
-
-$alert->addItem((new CTag('h4'))->addItem(I18n::t('sec.threshold')));
-$alert->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('lbl.threshold_hint')));
-$alert->addItem($sev_form);
 
-$tabs->addTab('alert', I18n::t('tab.alert'), $alert);
+$tab_alert = '<div class="wc-grid">'.$robotCard.$thresholdCard.$strategyCard.$previewCard.'</div>';
 
-/* ================================================================== */
-/*  TAB 2 - OPTIMIZATION                                               */
-/* ================================================================== */
-$opt = new CDiv();
+/* ======================== TAB 2: OPTIMIZATION ========================= */
 
-// --- 2a. Server tuning generator --------------------------------------
-$tune_sel = new CSelect('tuning_profile');
+// -- tuning --
+$tuneOpts = '';
 foreach (['small', 'medium', 'large'] as $pk) {
-	$tune_sel->addOption(new CSelectOption($pk, I18n::t('tuning.'.$pk)));
+	$tuneOpts .= '<option value="'.$e($pk).'"'.(($data['tuning_profile'] === $pk) ? ' selected' : '').'>'.$t($pk === 'small' ? 'tuning.small' : ($pk === 'medium' ? 'tuning.medium' : 'tuning.large')).'</option>';
 }
-$tune_sel->setValue($data['tuning_profile']);
-$tune_form = (new CForm('get', $view_url))
-	->addItem(
-		(new CFormList())->addRow(I18n::t('tuning.choose'), $tune_sel)
-	)
-	->addItem((new CSubmitButton(I18n::t('btn.generate'), 'generate', '1'))->addClass(ZBX_STYLE_BTN_ALT))
-	->setId('wc-tune');
+$tuneBody =
+	'<div class="wc-hint">'.$t('lbl.tuning_hint').'</div>'
+	.'<form method="get" action="zabbix.php"><input type="hidden" name="action" value="wecom.center.view">'
+	.'<input type="hidden" name="mediatypeid" value="'.$mtid.'">'
+	.'<div class="wc-inline"><div class="wc-field"><label>'.$t('tuning.choose').'</label>'
+	.'<select class="wc-input" name="tuning_profile">'.$tuneOpts.'</select></div>'
+	.'<button class="wc-btn wc-btn--primary" type="submit" name="generate" value="1">'.$t('btn.generate').'</button></div></form>'
+	.'<div class="wc-code__label" style="margin-top:16px">'.$t('tuning.env').'</div>'
+	.'<div class="wc-code">'.$e($data['tuning']['env']).'</div>'
+	.'<div class="wc-code__label">'.$t('tuning.cmd').'</div>'
+	.'<div class="wc-code">'.$e($data['tuning']['cmd']).'</div>';
+$tuningCard = $card('&#9881;&#65039;', $t('sec.tuning'), $tuneBody, ' wc-card--wide');
 
-$env_pre = (new CTag('pre'))->addItem($data['tuning']['env'])
-	->setAttribute('style', 'background:#f4f4f4;padding:8px;border:1px solid #ccc;font-family:monospace;');
-$cmd_pre = (new CTag('pre'))->addItem($data['tuning']['cmd'])
-	->setAttribute('style', 'background:#f4f4f4;padding:8px;border:1px solid #ccc;font-family:monospace;');
-
-$opt->addItem((new CTag('h4'))->addItem(I18n::t('sec.tuning')));
-$opt->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('lbl.tuning_hint')));
-$opt->addItem($tune_form);
-$opt->addItem((new CDiv())->addItem((new CTag('strong'))->addItem(I18n::t('tuning.env')))->addItem($env_pre));
-$opt->addItem((new CDiv())->addItem((new CTag('strong'))->addItem(I18n::t('tuning.cmd')))->addItem($cmd_pre));
-
-// --- 2b. Template import ---------------------------------------------
-$tpl_sel = new CSelect('template_file');
+// -- template import --
+$tplOpts = '';
 if (!$data['templates']) {
-	$tpl_sel->addOption(new CSelectOption('', I18n::t('tpl.none')));
+	$tplOpts = '<option value="">'.$t('tpl.none').'</option>';
 }
-foreach ($data['templates'] as $t) {
-	$tpl_sel->addOption(new CSelectOption($t['file'], $t['name']));
+foreach ($data['templates'] as $tf) {
+	$tplOpts .= '<option value="'.$e($tf['file']).'">'.$e($tf['name']).'</option>';
 }
-$tpl_form = (new CForm())
-	->addItem((new CFormList())->addRow(I18n::t('tpl.choose'), $tpl_sel))
-	->addItem((new CSubmitButton(I18n::t('btn.import'), 'op', 'import_template')))
-	->setAction($save_url)
-	->setId('wc-tpl');
-$opt->addItem((new CTag('h4'))->addItem(I18n::t('sec.template')));
-$opt->addItem($tpl_form);
+$importBody =
+	'<div class="wc-hint">'.$t('lbl.template_hint').'</div>'
+	.'<form method="post" action="'.$save.'">'
+	.'<div class="wc-field"><label>'.$t('tpl.choose').'</label><select class="wc-input" name="template_file">'.$tplOpts.'</select></div>'
+	.'<div class="wc-actions"><button class="wc-btn wc-btn--primary" type="submit" name="op" value="import_template">'.$t('btn.import').'</button></div>'
+	.'</form>';
+$importCard = $card('&#128230;', $t('sec.template'), $importBody);
 
-// --- 2c. Map marker (single point = Zabbix server host) --------------
+// -- map --
 if ($data['server_host']) {
-	$map_form = (new CForm())
-		->addItem((new CVar('hostid', $data['server_host']['hostid']))->removeId())
-		->addItem(
-			(new CFormList())
-				->addRow(I18n::t('map.host'),
-					(new CSpan($data['server_host']['name'])))
-				->addRow(I18n::t('map.lat'),
-					(new CTextBox('lat', $data['server_loc']['location_lat']))->setWidth(ZBX_TEXTAREA_SMALL_WIDTH))
-				->addRow(I18n::t('map.lon'),
-					(new CTextBox('lon', $data['server_loc']['location_lon']))->setWidth(ZBX_TEXTAREA_SMALL_WIDTH))
-		)
-		->addItem((new CSubmitButton(I18n::t('btn.save'), 'op', 'save_map')))
-		->setAction($save_url)
-		->setId('wc-map');
-	$opt->addItem((new CTag('h4'))->addItem(I18n::t('sec.map')));
-	$opt->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('map.hint')));
-	$opt->addItem($map_form);
+	$mapBody =
+		'<div class="wc-hint">'.$t('map.hint').'</div>'
+		.'<form method="post" action="'.$save.'">'
+		.'<input type="hidden" name="hostid" value="'.$e($data['server_host']['hostid']).'">'
+		.'<div class="wc-field"><label>'.$t('map.host').'</label><div class="wc-muted">'.$e($data['server_host']['name']).'</div></div>'
+		.'<div class="wc-inline">'
+		.'<div class="wc-field"><label>'.$t('map.lat').'</label><input class="wc-input" type="text" name="lat" value="'.$e($data['server_loc']['location_lat']).'"></div>'
+		.'<div class="wc-field"><label>'.$t('map.lon').'</label><input class="wc-input" type="text" name="lon" value="'.$e($data['server_loc']['location_lon']).'"></div>'
+		.'</div>'
+		.'<div class="wc-actions"><button class="wc-btn wc-btn--primary" type="submit" name="op" value="save_map">'.$t('btn.save').'</button></div>'
+		.'</form>';
 }
 else {
-	$opt->addItem((new CTag('h4'))->addItem(I18n::t('sec.map')));
-	$opt->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('msg.no_server_host')));
+	$mapBody = '<div class="wc-empty">'.$t('msg.no_server_host').'</div>';
 }
+$mapCard = $card('&#128506;&#65039;', $t('sec.map'), $mapBody);
 
-$tabs->addTab('opt', I18n::t('tab.opt'), $opt);
+// -- template switch --
+$srcOpts = '<option value="">'.$t('switch.pick').'</option>';
+$dstOpts = '<option value="">'.$t('switch.pick').'</option>';
+foreach ($data['huawei_tpls'] as $tp) {
+	$selS = ((string) $data['switch_src'] === (string) $tp['templateid']) ? ' selected' : '';
+	$selD = ((string) $data['switch_dst'] === (string) $tp['templateid']) ? ' selected' : '';
+	$srcOpts .= '<option value="'.$e($tp['templateid']).'"'.$selS.'>'.$e($tp['host']).'</option>';
+	$dstOpts .= '<option value="'.$e($tp['templateid']).'"'.$selD.'>'.$e($tp['host']).'</option>';
+}
+$switchBody =
+	'<div class="wc-hint">'.$t('lbl.switch_hint').'</div>'
+	.'<form method="get" action="zabbix.php"><input type="hidden" name="action" value="wecom.center.view">'
+	.'<input type="hidden" name="mediatypeid" value="'.$mtid.'">'
+	.'<div class="wc-inline">'
+	.'<div class="wc-field"><label>'.$t('switch.src').'</label><select class="wc-input" name="switch_src">'.$srcOpts.'</select></div>'
+	.'<div class="wc-field"><label>'.$t('switch.dst').'</label><select class="wc-input" name="switch_dst">'.$dstOpts.'</select></div>'
+	.'<button class="wc-btn wc-btn--ghost" type="submit" name="preview" value="1">'.$t('btn.preview').'</button>'
+	.'</div></form>';
 
-/* ================================================================== */
-/*  TAB 3 - MAINTENANCE (per-trigger alerting switch)                 */
-/* ================================================================== */
-$maint = new CDiv();
+if ($data['switch_preview'] !== null) {
+	$sp = $data['switch_preview'];
+	if ((int) $sp['count'] === 0) {
+		$switchBody .= '<div class="wc-divider"></div><div class="wc-empty">'.$t('switch.none', [$sp['src_name']]).'</div>';
+	}
+	else {
+		$chips = '';
+		foreach ($sp['hosts'] as $hn) {
+			$chips .= '<span class="wc-chip">'.$e($hn).'</span>';
+		}
+		$switchBody .= '<div class="wc-divider"></div>'
+			.'<div class="wc-muted">'.$t('switch.result', [$sp['count'], $sp['src_name'], $sp['dst_name']]).'</div>'
+			.'<div class="wc-chips">'.$chips.'</div>'
+			.'<form method="post" action="'.$save.'" style="margin-top:14px">'
+			.'<input type="hidden" name="switch_src" value="'.$e($sp['src']).'">'
+			.'<input type="hidden" name="switch_dst" value="'.$e($sp['dst']).'">'
+			.'<button class="wc-btn wc-btn--danger" type="submit" name="op" value="apply_switch">'.$t('btn.confirm').'</button>'
+			.'</form>';
+	}
+}
+$switchCard = $card('&#128257;', $t('sec.switch'), $switchBody, ' wc-card--wide');
+
+$tab_opt = '<div class="wc-grid">'.$tuningCard.$importCard.$mapCard.$switchCard.'</div>';
 
-$trig_search_form = (new CForm('get', $view_url))
-	->addItem((new CTextBox('trig_search', $data['trig_search']))
-		->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
-		->setAttribute('placeholder', I18n::t('lbl.trig_search')))
-	->addItem((new CSubmitButton(I18n::t('btn.search'), 'search', '1'))->addClass(ZBX_STYLE_BTN_ALT))
-	->setId('trig-search-form');
+/* ======================== TAB 3: MAINTENANCE ========================== */
 
-$maint->addItem((new CTag('h4'))->addItem(I18n::t('sec.triggers')));
-$maint->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('lbl.trig_hint', [$data['trigger_count']])));
-$maint->addItem($trig_search_form);
+$searchBody =
+	'<div class="wc-hint">'.$t('lbl.trig_hint', [$data['trigger_count']]).'</div>'
+	.'<form method="get" action="zabbix.php"><input type="hidden" name="action" value="wecom.center.view">'
+	.'<input type="hidden" name="mediatypeid" value="'.$mtid.'">'
+	.'<div class="wc-inline"><div class="wc-field" style="flex:3"><input class="wc-input" type="text" name="trig_search" value="'.$e($data['trig_search']).'" placeholder="'.$t('lbl.trig_search').'"></div>'
+	.'<button class="wc-btn wc-btn--primary" type="submit" name="search" value="1">'.$t('btn.search').'</button></div></form>';
+$maintBody = $searchBody;
 
 if ($data['trig_search'] !== '') {
 	if ($data['triggers']) {
-		$trig_list = new CList();
 		$ids = [];
-		foreach ($data['triggers'] as $t) {
-			$ids[] = $t['triggerid'];
-			$host = !empty($t['hosts']) ? $t['hosts'][0]['host'] : '';
-			$sev_name = I18n::t('sev.'.(((int) $t['priority']) + 1));
-			$label = '['.$sev_name.'] '.$host.' — '.$t['description'];
-			$trig_list->addItem(
-				(new CCheckBox('trig_'.$t['triggerid']))->setLabel($label)->setChecked(((int) $t['status']) === 0)
-			);
+		$list = '';
+		foreach ($data['triggers'] as $tg) {
+			$ids[] = $tg['triggerid'];
+			$host = !empty($tg['hosts']) ? $tg['hosts'][0]['host'] : '';
+			$sev = ((int) $tg['priority']) + 1;
+			$chk = ((int) $tg['status'] === 0) ? ' checked' : '';
+			$list .= '<label class="wc-checkrow" style="display:block;padding:6px 0;border-bottom:1px solid #f2f4f7">'
+				.'<input type="checkbox" name="trig_'.$e($tg['triggerid']).'"'.$chk.'> '
+				.'<span class="wc-sev wc-sev-'.$sev.'">'.$t('sev.'.$sev).'</span> '
+				.'<span class="wc-muted">'.$e($host).'</span> — '.$e($tg['description']).'</label>';
 		}
-		$trig_save_form = (new CForm())
-			->addItem((new CVar('trig_ids', implode(',', $ids)))->removeId())
-			->addItem((new CFormList())->addRow(I18n::t('lbl.trig_list'), $trig_list))
-			->addItem((new CSubmitButton(I18n::t('btn.save'), 'op', 'save_triggers')))
-			->setAction($save_url)
-			->setId('wc-trig');
-		$maint->addItem($trig_save_form);
+		$maintBody .= '<div class="wc-divider"></div>'
+			.'<form method="post" action="'.$save.'">'
+			.'<input type="hidden" name="trig_ids" value="'.$e(implode(',', $ids)).'">'
+			.'<div class="wc-field"><label>'.$t('lbl.trig_list').'</label>'.$list.'</div>'
+			.'<div class="wc-actions"><button class="wc-btn wc-btn--primary" type="submit" name="op" value="save_triggers">'.$t('btn.save').'</button></div>'
+			.'</form>';
 	}
 	else {
-		$maint->addItem(new CDiv(new CTag('p'))->addItem(I18n::t('msg.no_trig_search')));
+		$maintBody .= '<div class="wc-divider"></div><div class="wc-empty">'.$t('msg.no_trig_search').'</div>';
 	}
 }
+$tab_maint = '<div class="wc-grid">'.$card('&#128295;', $t('sec.triggers'), $maintBody, ' wc-card--wide').'</div>';
 
-$tabs->addTab('maint', I18n::t('tab.maint'), $maint);
+/* ============================ assemble =============================== */
+$hero = '<div class="wc-hero"><div class="wc-hero__title">'.$t('page.title').'</div>'
+	.'<div class="wc-hero__sub">'.$t('hero.sub').'</div></div>';
+
+$tabs = new CTabView();
+$tabs->addTab('alert', I18n::t('tab.alert'), '<div class="wc-wrap">'.$hero.$tab_alert.'</div>');
+$tabs->addTab('opt', I18n::t('tab.opt'), '<div class="wc-wrap">'.$tab_opt.'</div>');
+$tabs->addTab('maint', I18n::t('tab.maint'), '<div class="wc-wrap">'.$tab_maint.'</div>');
 
 $html_page->addItem($tabs);
 $html_page->show();