This is an automated email from the ASF dual-hosted git repository.
zhaoqingran pushed a commit to branch bulletin
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/bulletin by this push:
new bdda79bca [feat(bulletin)] implement tree structure for metric
selection
bdda79bca is described below
commit bdda79bcaa9fa65ff1f1971defa5c0f8ad03aa71
Author: zqr10159 <[email protected]>
AuthorDate: Wed Jul 10 17:30:42 2024 +0800
[feat(bulletin)] implement tree structure for metric selection
Replace the existing metric dropdown in the bulletin component with a
tree structure to facilitate hierarchical metric selection. This new
interface allows users to navigate and choose metrics in a more intuitive
and visual manner.
---
.../manager/controller/AppController.java | 12 ++
.../hertzbeat/manager/service/AppService.java | 9 +
.../manager/service/impl/AppServiceImpl.java | 87 +++++++-
.../app/routes/bulletin/bulletin.component.html | 134 +++---------
.../src/app/routes/bulletin/bulletin.component.ts | 226 ++++++++++++---------
web-app/src/app/routes/routes.module.ts | 40 ++--
web-app/src/app/service/app-define.service.ts | 10 +
7 files changed, 289 insertions(+), 229 deletions(-)
diff --git
a/manager/src/main/java/org/apache/hertzbeat/manager/controller/AppController.java
b/manager/src/main/java/org/apache/hertzbeat/manager/controller/AppController.java
index 7d6b5cc84..5472f0f39 100644
---
a/manager/src/main/java/org/apache/hertzbeat/manager/controller/AppController.java
+++
b/manager/src/main/java/org/apache/hertzbeat/manager/controller/AppController.java
@@ -161,6 +161,18 @@ public class AppController {
return ResponseEntity.ok(Message.success(appHierarchies));
}
+ @GetMapping(path = "/hierarchy/{app}")
+ @Operation(summary = "Query all monitor metrics level, output in a
hierarchical structure", description = "Query all monitor metrics level, output
in a hierarchical structure")
+ public ResponseEntity<Message<List<Hierarchy>>> queryAppsHierarchyByApp(
+ @Parameter(description = "en: language type",
+ example = "zh-CN")
+ @RequestParam(name = "lang", required = false) String lang,
+ @Parameter(description = "en: Monitoring type name", example =
"api") @PathVariable("app") final String app) {
+ lang = getLang(lang);
+ List<Hierarchy> appHierarchies = appService.getAppHierarchy(app, lang);
+ return ResponseEntity.ok(Message.success(appHierarchies));
+ }
+
@GetMapping(path = "/defines")
@Operation(summary = "Query all monitor types", description = "Query all
monitor types")
public ResponseEntity<Message<Map<String, String>>> getAllAppDefines(
diff --git
a/manager/src/main/java/org/apache/hertzbeat/manager/service/AppService.java
b/manager/src/main/java/org/apache/hertzbeat/manager/service/AppService.java
index 2e4de7a5b..21144afb6 100644
--- a/manager/src/main/java/org/apache/hertzbeat/manager/service/AppService.java
+++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/AppService.java
@@ -96,6 +96,15 @@ public interface AppService {
*/
List<Hierarchy> getAllAppHierarchy(String lang);
+ /**
+ * Get the monitoring hierarchy based on the monitoring type
+ *
+ * @param app monitoring type
+ * @param lang language
+ * @return hierarchy information
+ */
+ List<Hierarchy> getAppHierarchy(String app, String lang);
+
/**
* Get all app define
*
diff --git
a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/AppServiceImpl.java
b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/AppServiceImpl.java
index 1e861a006..1fbf998d4 100644
---
a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/AppServiceImpl.java
+++
b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/AppServiceImpl.java
@@ -340,13 +340,95 @@ public class AppServiceImpl implements AppService,
CommandLineRunner {
return hierarchies;
}
+ @Override
+ public List<Hierarchy> getAppHierarchy(String app, String lang) {
+ LinkedList<Hierarchy> hierarchies = new LinkedList<>();
+ Job job = appDefines.get(app.toLowerCase());
+ // TODO temporarily filter out push to solve the front-end problem,
and open it after the subsequent design optimization
+ if (DispatchConstants.PROTOCOL_PUSH.equalsIgnoreCase(job.getApp())) {
+ return hierarchies;
+ }
+ var hierarchyApp = new Hierarchy();
+ hierarchyApp.setCategory(job.getCategory());
+ hierarchyApp.setValue(job.getApp());
+ hierarchyApp.setHide(job.isHide());
+ var nameMap = job.getName();
+ if (nameMap != null && !nameMap.isEmpty()) {
+ var i18nName = CommonUtil.getLangMappingValueFromI18nMap(lang,
nameMap);
+ if (i18nName != null) {
+ hierarchyApp.setLabel(i18nName);
+ }
+ }
+ List<Hierarchy> hierarchyMetricList = new LinkedList<>();
+ if
(DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(job.getApp())) {
+ List<Monitor> monitors =
monitorDao.findMonitorsByAppEquals(job.getApp());
+ for (Monitor monitor : monitors) {
+ List<CollectRep.MetricsData> metricsDataList =
warehouseService.queryMonitorMetricsData(monitor.getId());
+ for (CollectRep.MetricsData metricsData : metricsDataList) {
+ var hierarchyMetric = new Hierarchy();
+ hierarchyMetric.setValue(metricsData.getMetrics());
+ hierarchyMetric.setLabel(metricsData.getMetrics());
+ List<Hierarchy> hierarchyFieldList =
metricsData.getFieldsList().stream()
+ .map(item -> {
+ var hierarchyField = new Hierarchy();
+ hierarchyField.setValue(item.getName());
+ hierarchyField.setLabel(item.getName());
+ hierarchyField.setIsLeaf(true);
+ hierarchyField.setType((byte) item.getType());
+ hierarchyField.setUnit(item.getUnit());
+ return hierarchyField;
+ }).collect(Collectors.toList());
+ hierarchyMetric.setChildren(hierarchyFieldList);
+ // combine Hierarchy Metrics
+ combineHierarchyMetrics(hierarchyMetricList,
hierarchyMetric);
+ }
+ }
+ hierarchyApp.setChildren(hierarchyMetricList);
+ hierarchies.addFirst(hierarchyApp);
+ } else {
+ if (job.getMetrics() != null) {
+ for (var metrics : job.getMetrics()) {
+ var hierarchyMetric = new Hierarchy();
+ hierarchyMetric.setValue(metrics.getName());
+ var metricsI18nName =
CommonUtil.getLangMappingValueFromI18nMap(lang, metrics.getI18n());
+ hierarchyMetric.setLabel(metricsI18nName != null ?
metricsI18nName : metrics.getName());
+ List<Hierarchy> hierarchyFieldList = new LinkedList<>();
+ if (metrics.getFields() != null) {
+ for (var field : metrics.getFields()) {
+ var hierarchyField = new Hierarchy();
+ hierarchyField.setValue(field.getField());
+ var metricI18nName =
CommonUtil.getLangMappingValueFromI18nMap(lang, field.getI18n());
+ hierarchyField.setLabel(metricI18nName != null ?
metricI18nName : field.getField());
+ hierarchyField.setIsLeaf(true);
+ // for metric
+ hierarchyField.setType(field.getType());
+ hierarchyField.setUnit(field.getUnit());
+ hierarchyFieldList.add(hierarchyField);
+ }
+ hierarchyMetric.setChildren(hierarchyFieldList);
+ }
+ hierarchyMetricList.add(hierarchyMetric);
+ }
+ }
+ hierarchyApp.setChildren(hierarchyMetricList);
+ hierarchies.add(hierarchyApp);
+ }
+ return hierarchies;
+ }
+
+
private void combineHierarchyMetrics(List<Hierarchy> hierarchyMetricList,
Hierarchy hierarchyMetric) {
Optional<Hierarchy> preHierarchyOptional = hierarchyMetricList.stream()
- .filter(item ->
item.getValue().equals(hierarchyMetric.getValue())).findFirst();
+ .filter(item ->
item.getValue().equals(hierarchyMetric.getValue()))
+ .findFirst();
+
if (preHierarchyOptional.isPresent()) {
Hierarchy preHierarchy = preHierarchyOptional.get();
List<Hierarchy> children = preHierarchy.getChildren();
- Set<String> childrenKey =
children.stream().map(Hierarchy::getValue).collect(Collectors.toSet());
+ Set<String> childrenKey = children.stream()
+ .map(Hierarchy::getValue)
+ .collect(Collectors.toSet());
+
for (Hierarchy child : hierarchyMetric.getChildren()) {
if (!childrenKey.contains(child.getValue())) {
children.add(child);
@@ -357,6 +439,7 @@ public class AppServiceImpl implements AppService,
CommandLineRunner {
}
}
+
@Override
public Map<String, Job> getAllAppDefines() {
return appDefines;
diff --git a/web-app/src/app/routes/bulletin/bulletin.component.html
b/web-app/src/app/routes/bulletin/bulletin.component.html
index 0529d92db..ddd35a741 100644
--- a/web-app/src/app/routes/bulletin/bulletin.component.html
+++ b/web-app/src/app/routes/bulletin/bulletin.component.html
@@ -146,7 +146,6 @@
[(ngModel)]="define.app"
(nzOnSearch)="onSearchAppDefines()"
(ngModelChange)="onAppChange($event)"
-
>
<ng-container *ngFor="let app of appEntries">
<nz-option *ngIf="isAppListLoading" [nzValue]="app.key"
[nzLabel]="app.key + '/' + app.value"></nz-option>
@@ -155,116 +154,31 @@
</nz-form-control>
</nz-form-item>
<nz-form-item>
- <nz-transfer
- name="metrics"
- [nzDataSource]="this.currentMetrics"
- [(ngModel)]="define.metrics"
- nzShowSearch
- ></nz-transfer>
+ <nz-form-label [nzSpan]="7" nzFor="dropdown" nzRequired="true">{{
'dropdown.label' | i18n }}</nz-form-label>
+ <nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' |
i18n">
+ <nz-transfer [nzDataSource]="treeNodes"
[nzRenderList]="[leftRenderList, null]" (nzChange)="transferChange($event)">
+ <ng-template #leftRenderList let-items
let-onItemSelect="onItemSelect">
+ <nz-tree
+ [nzData]="treeNodes"
+ nzExpandAll
+ nzBlockNode
+ nzCheckable
+ nzCheckStrictly
+ (nzCheckBoxChange)="treeCheckBoxChange($event, onItemSelect)"
+ >
+ <ng-template let-node>
+ <span
+ (click)="checkBoxChange(node, onItemSelect)"
+ class="ant-tree-node-content-wrapper
ant-tree-node-content-wrapper-open"
+ >
+ {{ node.title }}
+ </span>
+ </ng-template>
+ </nz-tree>
+ </ng-template>
+ </nz-transfer>
+ </nz-form-control>
</nz-form-item>
</form>
</div>
</nz-modal>
-
-<!-- 选择TAG弹出框 -->
-<nz-modal
- [(nzVisible)]="isTagManageModalVisible"
- [nzTitle]="'tag.bind' | i18n"
- (nzOnCancel)="onTagManageModalCancel()"
- (nzOnOk)="onTagManageModalOk()"
- nzMaskClosable="false"
- nzWidth="30%"
- [nzOkLoading]="isTagManageModalOkLoading"
->
- <div *nzModalContent class="-inner-content">
- <input
- style="margin-left: 5px; width: 50%; text-align: center"
- nz-input
- type="text"
- [placeholder]="'tag.search' | i18n"
- nzSize="default"
- (keyup.enter)="loadTagsTable()"
- [(ngModel)]="tagSearch"
- />
- <button nz-button nzType="primary" routerLink="/setting/tags"
style="margin-left: 5px">
- <i nz-icon nzType="setting" nzTheme="outline"></i>
- {{ 'tag.setting' | i18n }}
- </button>
- <nz-table #smallTable nzSize="small" [nzData]="tags" [nzPageSize]="8"
[nzLoading]="tagTableLoading">
- <thead>
- <tr>
- <th nzAlign="center" nzLeft nzWidth="4%"
[(nzChecked)]="tagCheckedAll" (nzCheckedChange)="onTagAllChecked($event)"></th>
- <th nzAlign="left">{{ 'tag' | i18n }}</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let data of smallTable.data">
- <td nzAlign="center" nzLeft [nzChecked]="checkedTags.has(data)"
(nzCheckedChange)="onTagItemChecked(data, $event)"></td>
- <td nzAlign="left">
- <nz-tag *ngIf="data.tagValue == undefined || data.tagValue.trim()
== ''" [nzColor]="data.color">{{ data.name }}</nz-tag>
- <nz-tag *ngIf="data.tagValue != undefined && data.tagValue.trim()
!= ''" [nzColor]="data.color">
- {{ data.name + ':' + data.tagValue }}
- </nz-tag>
- </td>
- </tr>
- </tbody>
- </nz-table>
- </div>
-</nz-modal>
-
-<!-- 关联告警定义与监控关系弹出框 -->
-
-<nz-modal
- [(nzVisible)]="isConnectModalVisible"
- [nzTitle]="'alert.setting.connect' | i18n"
- (nzOnCancel)="onConnectModalCancel()"
- (nzOnOk)="onConnectModalOk()"
- nzMaskClosable="false"
- nzWidth="60%"
- [nzOkLoading]="isConnectModalOkLoading"
->
- <nz-transfer
- *nzModalContent
- [nzDataSource]="transferData"
- nzShowSearch="true"
- nzShowSelectAll="false"
- [nzRenderList]="[renderList, renderList]"
- (nzChange)="change($event)"
- style="overflow-x: scroll"
- >
- <ng-template
- #renderList
- let-items
- let-direction="direction"
- let-stat="stat"
- let-onItemSelectAll="onItemSelectAll"
- let-onItemSelect="onItemSelect"
- >
- <nz-table #t [nzData]="$asTransferItems(items)" nzSize="small">
- <thead>
- <tr>
- <th [nzChecked]="stat.checkAll" [nzIndeterminate]="stat.checkHalf"
(nzCheckedChange)="onItemSelectAll($event)"></th>
- <th *ngIf="direction == 'left'">{{ 'alert.setting.connect.left' |
i18n }}</th>
- <th *ngIf="direction == 'right'">{{ 'alert.setting.connect.right'
| i18n }}</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let data of t.data" (click)="onItemSelect(data)">
- <td [nzChecked]="!!data.checked"
(nzCheckedChange)="onItemSelect(data)"></td>
- <td>{{ data.name }}</td>
- </tr>
- </tbody>
- </nz-table>
- </ng-template>
- </nz-transfer>
-</nz-modal>
-
-<!-- 导出告警定义弹出框 -->
-<nz-modal
- [(nzVisible)]="isSwitchExportTypeModalVisible"
- [nzTitle]="'alert.export.switch-type' | i18n"
- (nzOnCancel)="onExportTypeModalCancel()"
- nzOkDisabled="true"
- [nzFooter]="switchExportTypeModalFooter"
->
-</nz-modal>
diff --git a/web-app/src/app/routes/bulletin/bulletin.component.ts
b/web-app/src/app/routes/bulletin/bulletin.component.ts
index 2291d4427..90e2d83b7 100644
--- a/web-app/src/app/routes/bulletin/bulletin.component.ts
+++ b/web-app/src/app/routes/bulletin/bulletin.component.ts
@@ -25,7 +25,7 @@ import { ModalButtonOptions, NzModalService } from
'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { NzTableQueryParams } from 'ng-zorro-antd/table';
import { TransferChange, TransferItem } from 'ng-zorro-antd/transfer';
-import { NzUploadChangeParam } from 'ng-zorro-antd/upload';
+import { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from
'ng-zorro-antd/tree';
import { zip } from 'rxjs';
import { finalize, map } from 'rxjs/operators';
@@ -67,44 +67,16 @@ export class BulletinComponent implements OnInit {
checkedDefineIds = new Set<number>();
isSwitchExportTypeModalVisible = false;
isAppListLoading = false;
- appHierarchies!: any[];
- appMap = new Map<string, string>();
- appEntries: { value: any; key: string }[] = [];
+ treeNodes!: NzTreeNodeOptions[];
+ hierarchies: TransferItem[] = [];
+ appMap = new Map<string, string>();
+ appEntries: Array<{ value: any; key: string }> = [];
+ checkedNodeList: NzTreeNode[] = [];
switchExportTypeModalFooter: ModalButtonOptions[] = [
{ label: this.i18nSvc.fanyi('common.button.cancel'), type: 'default',
onClick: () => (this.isSwitchExportTypeModalVisible = false) }
];
ngOnInit(): void {
this.loadBulletinDefineTable();
- // 查询监控层级
- const getHierarchy$ = this.appDefineSvc
- .getAppHierarchy(this.i18nSvc.defaultLang)
- .pipe(
- finalize(() => {
- getHierarchy$.unsubscribe();
- })
- )
- .subscribe(
- message => {
- if (message.code === 0) {
- this.appHierarchies = message.data;
- this.appHierarchies.forEach(item => {
- if (item.children == undefined) {
- item.children = [];
- }
- item.children.unshift({
- value: AVAILABILITY,
- label: this.i18nSvc.fanyi('monitor.availability'),
- isLeaf: true
- });
- });
- } else {
- console.warn(message.msg);
- }
- },
- error => {
- console.warn(error.msg);
- }
- );
}
sync() {
@@ -319,7 +291,6 @@ export class BulletinComponent implements OnInit {
isManageModalAdd = true;
define: BulletinDefine = new BulletinDefine();
cascadeValues: string[] = [];
- currentMetrics: TransferItem[] = [];
alertRules: any[] = [{}];
isExpr = false;
caseInsensitiveFilter: NzCascaderFilter = (i, p) => {
@@ -329,7 +300,6 @@ export class BulletinComponent implements OnInit {
});
};
-
onManageModalCancel() {
this.isExpr = false;
this.isManageModalVisible = false;
@@ -548,81 +518,141 @@ export class BulletinComponent implements OnInit {
}
);
}
- change(ret: TransferChange): void {
- const listKeys = ret.list.map(l => l.key);
- const hasOwnKey = (e: TransferItem): boolean => e.hasOwnProperty('key');
- this.transferData = this.transferData.map(e => {
- if (listKeys.includes(e.key) && hasOwnKey(e)) {
- if (ret.to === 'left') {
- delete e.hide;
- } else if (ret.to === 'right') {
- e.hide = false;
+ // 获取应用定义
+ onSearchAppDefines(): void {
+ this.appDefineSvc
+ .getAppDefines(this.i18nSvc.defaultLang)
+ .pipe()
+ .subscribe(
+ message => {
+ if (message.code === 0) {
+ this.appMap = message.data;
+ this.appEntries = Object.entries(this.appMap).map(([key, value])
=> ({ key, value }));
+ if (this.appEntries != null) {
+ this.isAppListLoading = true;
+ }
+ } else {
+ console.warn(message.msg);
+ }
+ },
+ error => {
+ console.warn(error.msg);
}
- }
- return e;
- });
+ );
}
- filterMetrics(currentMetrics: any[], cascadeValues: any): any[] {
- if (cascadeValues.length !== 3) {
- return currentMetrics;
+
+ // 应用改变事件
+ onAppChange(appKey: string): void {
+ if (appKey) {
+ this.onSearchTreeNodes(appKey);
+ } else {
+ this.hierarchies = [];
+ this.treeNodes = [];
}
- // sort the cascadeValues[2] to first
- return currentMetrics.sort((a, b) => {
- if (a.value !== cascadeValues[2]) {
- return 1;
- } else {
- return -1;
- }
- });
}
- // end 告警定义与监控关联model
- // SearchAppDefines
- onSearchAppDefines(): void {
- this.appDefineSvc.getAppDefines(this.i18nSvc.defaultLang).pipe().subscribe(
- message => {
- if (message.code === 0) {
- this.appMap = message.data;
- this.appEntries = Object.entries(this.appMap).map(([key, value]) =>
({ key, value }));
- if (this.appEntries != null) {
- this.isAppListLoading = true;
+
+ // 获取树节点
+ onSearchTreeNodes(app: string): void {
+ this.appDefineSvc
+ .getAppHierarchyByName(this.i18nSvc.defaultLang, app)
+ .pipe()
+ .subscribe(
+ message => {
+ if (message.code === 0) {
+ this.hierarchies = this.transformToTransferItems(message.data);
+ this.treeNodes = this.transformToTreeData(message.data);
+ } else {
+ console.warn(message.msg);
}
- } else {
- console.warn(message.msg);
+ },
+ error => {
+ console.warn(error.msg);
}
- },
- error => {
- console.warn(error.msg);
- }
- )
+ );
}
- onAppChange(appKey: string): void {
- if (appKey) {
- this.onSearchMetricsByApp(appKey);
+ // 转换为 TransferItem
+ transformToTransferItems(data: any[]): TransferItem[] {
+ const result: TransferItem[] = [];
+ const traverse = (nodes: any[], parentKey: string | null = null) => {
+ nodes.forEach(node => {
+ if (node.isLeaf) {
+ const key = parentKey ? `${parentKey}-${node.value}` : node.value;
+ result.push({
+ key,
+ title: node.label,
+ direction: 'left',
+ checked: false,
+ isLeaf: node.isLeaf,
+ hide: node.hide
+ });
+ }
+ if (node.children) {
+ traverse(node.children, parentKey ? `${parentKey}-${node.value}` :
node.value);
+ }
+ });
+ };
+ traverse(data);
+ return result;
+ }
+
+
+
+ transformToTreeData(data: any[]): NzTreeNodeOptions[] {
+ const transformNode = (node: any): NzTreeNodeOptions => {
+ return {
+ title: node.label,
+ key: node.value,
+ isLeaf: node.isLeaf,
+ children: node.children ? node.children.map(transformNode) : []
+ };
+ };
+
+ // 假设最外层节点只有一个
+ const rootNode = data[0];
+ return rootNode.children ? rootNode.children.map(transformNode) : [];
+ }
+
+
+
+ // 树节点勾选事件
+ treeCheckBoxChange(event: NzFormatEmitEvent, onItemSelect: (item:
TransferItem) => void): void {
+ this.checkBoxChange(event.node!, onItemSelect);
+ }
+
+ // 勾选改变事件
+ checkBoxChange(node: NzTreeNode, onItemSelect: (item: TransferItem) =>
void): void {
+ if (node.isDisabled) {
+ return;
+ }
+ if (node.isChecked) {
+ this.checkedNodeList.push(node);
} else {
- this.currentMetrics = [];
+ const idx = this.checkedNodeList.indexOf(node);
+ if (idx !== -1) {
+ this.checkedNodeList.splice(idx, 1);
+ }
+ }
+ const item = this.treeNodes.find(w => w.key === node.key);
+ if (item) {
+ item.checked = node.isChecked;
+ onItemSelect(item);
}
}
- onSearchMetricsByApp(app: string): void {
- this.monitorSvc.getMonitorByApp(app).pipe().subscribe(
- message => {
- if (message.code === 0) {
- if (message.data != null && message.data.length > 0) {
- this.currentMetrics = message.data.map((metric: any) => ({
- key: metric,
- title: metric,
- description: metric,
- direction: 'left'
- }));}
- } else {
- console.warn(message.msg);
- }
- },
- error => {
- console.warn(error.msg);
+ // 穿梭框改变事件
+ transferChange(ret: TransferChange): void {
+ const isDisabled = ret.to === 'right';
+ this.checkedNodeList.forEach(node => {
+ node.isDisabled = isDisabled;
+ node.isChecked = isDisabled;
+ });
+ this.treeNodes = this.treeNodes.map(item => {
+ if (ret.list.some(i => i.key === item.key)) {
+ item.direction = ret.to;
}
- )
+ return item;
+ });
}
}
diff --git a/web-app/src/app/routes/routes.module.ts
b/web-app/src/app/routes/routes.module.ts
index 89029ec6e..e0dc6740f 100644
--- a/web-app/src/app/routes/routes.module.ts
+++ b/web-app/src/app/routes/routes.module.ts
@@ -24,29 +24,31 @@ import {NzUploadModule} from "ng-zorro-antd/upload";
import {NzCascaderModule} from "ng-zorro-antd/cascader";
import {NzTransferModule} from "ng-zorro-antd/transfer";
import {NzSwitchComponent} from "ng-zorro-antd/switch";
+import {NzTreeComponent} from "ng-zorro-antd/tree";
const COMPONENTS: Array<Type<void>> = [DashboardComponent, UserLoginComponent,
UserLockComponent, StatusPublicComponent, BulletinComponent];
@NgModule({
- imports: [
- SharedModule,
- RouteRoutingModule,
- NgxEchartsModule,
- NzTagModule,
- NzTimelineModule,
- SlickCarouselModule,
- TagCloudComponent,
- NzDividerModule,
- LayoutModule,
- NzCollapseModule,
- NzListModule,
- CommonModule,
- NzRadioModule,
- NzUploadModule,
- NzCascaderModule,
- NzTransferModule,
- NzSwitchComponent
- ],
+ imports: [
+ SharedModule,
+ RouteRoutingModule,
+ NgxEchartsModule,
+ NzTagModule,
+ NzTimelineModule,
+ SlickCarouselModule,
+ TagCloudComponent,
+ NzDividerModule,
+ LayoutModule,
+ NzCollapseModule,
+ NzListModule,
+ CommonModule,
+ NzRadioModule,
+ NzUploadModule,
+ NzCascaderModule,
+ NzTransferModule,
+ NzSwitchComponent,
+ NzTreeComponent
+ ],
declarations: COMPONENTS
})
export class RoutesModule {}
diff --git a/web-app/src/app/service/app-define.service.ts
b/web-app/src/app/service/app-define.service.ts
index 0474aa2a3..b9e246b30 100644
--- a/web-app/src/app/service/app-define.service.ts
+++ b/web-app/src/app/service/app-define.service.ts
@@ -98,6 +98,16 @@ export class AppDefineService {
return this.http.get<Message<any>>(app_hierarchy, options);
}
+ public getAppHierarchyByName(lang: string | undefined, app: string):
Observable<Message<any>> {
+ if (lang == undefined) {
+ lang = 'en_US';
+ }
+ let httpParams = new HttpParams().append('lang', lang);
+ const options = { params: httpParams };
+ return this.http.get<Message<any>>(`${app_hierarchy}/${app}`, options);
+ }
+
+
public getAppDefines(lang: string | undefined): Observable<Message<any>> {
if (lang == undefined) {
lang = 'en_US';
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]