Browse Source

UI: Fixed queue statistics

pull/10928/head
Artem Dzhereleiko 2 years ago
parent
commit
db774eacf9
  1. 16
      ui-ngx/src/app/core/http/entity.service.ts
  2. 11
      ui-ngx/src/app/core/http/queue.service.ts
  3. 5
      ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html
  4. 17
      ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts
  5. 22
      ui-ngx/src/app/shared/components/entity/entity-list.component.ts
  6. 1
      ui-ngx/src/app/shared/components/entity/entity-select.component.html
  7. 5
      ui-ngx/src/app/shared/components/entity/entity-select.component.ts
  8. 8
      ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts
  9. 6
      ui-ngx/src/app/shared/models/entity-type.models.ts
  10. 6
      ui-ngx/src/app/shared/models/queue.models.ts
  11. 9
      ui-ngx/src/assets/locale/locale.constant-en_US.json

16
ui-ngx/src/app/core/http/entity.service.ts

@ -169,6 +169,8 @@ export class EntityService {
case EntityType.QUEUE: case EntityType.QUEUE:
observable = this.queueService.getQueueById(entityId, config); observable = this.queueService.getQueueById(entityId, config);
break; break;
case EntityType.QUEUE_STATS:
observable = this.queueService.getQueueStatisticsById(entityId, config);
} }
return observable; return observable;
} }
@ -267,6 +269,11 @@ export class EntityService {
case EntityType.NOTIFICATION_TARGET: case EntityType.NOTIFICATION_TARGET:
observable = this.notificationService.getNotificationTargetsByIds(entityIds, config); observable = this.notificationService.getNotificationTargetsByIds(entityIds, config);
break; break;
case EntityType.QUEUE_STATS:
observable = this.getEntitiesByIdsObservable(
(id) => this.queueService.getQueueStatisticsById(id, config),
entityIds);
break;
} }
return observable; return observable;
} }
@ -444,6 +451,9 @@ export class EntityService {
pageLink.sortOrder.property = 'title'; pageLink.sortOrder.property = 'title';
entitiesObservable = this.resourceService.getTenantResources(pageLink, config); entitiesObservable = this.resourceService.getTenantResources(pageLink, config);
break; break;
case EntityType.QUEUE_STATS:
pageLink.sortOrder.property = 'createdTime';
entitiesObservable = this.queueService.getQueueStatistics(pageLink, config);
} }
return entitiesObservable; return entitiesObservable;
} }
@ -701,7 +711,7 @@ export class EntityService {
} }
public prepareAllowedEntityTypesList(allowedEntityTypes: Array<EntityType | AliasEntityType>, public prepareAllowedEntityTypesList(allowedEntityTypes: Array<EntityType | AliasEntityType>,
useAliasEntityTypes?: boolean): Array<EntityType | AliasEntityType> { useAliasEntityTypes?: boolean, addQueueStats = false): Array<EntityType | AliasEntityType> {
const authState = getCurrentAuthState(this.store); const authState = getCurrentAuthState(this.store);
const entityTypes: Array<EntityType | AliasEntityType> = []; const entityTypes: Array<EntityType | AliasEntityType> = [];
switch (authState.authUser.authority) { switch (authState.authUser.authority) {
@ -716,7 +726,9 @@ export class EntityService {
entityTypes.push(EntityType.CUSTOMER); entityTypes.push(EntityType.CUSTOMER);
entityTypes.push(EntityType.USER); entityTypes.push(EntityType.USER);
entityTypes.push(EntityType.DASHBOARD); entityTypes.push(EntityType.DASHBOARD);
entityTypes.push(EntityType.QUEUE_STATS); if (addQueueStats) {
entityTypes.push(EntityType.QUEUE_STATS);
}
if (authState.edgesSupportEnabled) { if (authState.edgesSupportEnabled) {
entityTypes.push(EntityType.EDGE); entityTypes.push(EntityType.EDGE);
} }

11
ui-ngx/src/app/core/http/queue.service.ts

@ -18,7 +18,7 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils'; import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { QueueInfo, ServiceType } from '@shared/models/queue.models'; import { QueueInfo, QueueStatisticsInfo, ServiceType } from '@shared/models/queue.models';
import { PageLink } from '@shared/models/page/page-link'; import { PageLink } from '@shared/models/page/page-link';
import { PageData } from '@shared/models/page/page-data'; import { PageData } from '@shared/models/page/page-data';
@ -53,4 +53,13 @@ export class QueueService {
public deleteQueue(queueId: string) { public deleteQueue(queueId: string) {
return this.http.delete(`/api/queues/${queueId}`); return this.http.delete(`/api/queues/${queueId}`);
} }
public getQueueStatistics(pageLink: PageLink, config?: RequestConfig): Observable<PageData<QueueStatisticsInfo>> {
return this.http.get<PageData<QueueStatisticsInfo>>(`/api/queueStats${pageLink.toQuery()}`,
defaultHttpOptionsFromConfig(config));
}
public getQueueStatisticsById(queueStatId: string, config?: RequestConfig): Observable<QueueStatisticsInfo> {
return this.http.get<QueueStatisticsInfo>(`/api/queueStats/${queueStatId}`, defaultHttpOptionsFromConfig(config));
}
} }

5
ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html

@ -29,7 +29,7 @@
</mat-form-field> </mat-form-field>
<section fxLayout="column" [formGroup]="filterFormGroup" [ngSwitch]="entityFilterFormGroup.get('type').value"> <section fxLayout="column" [formGroup]="filterFormGroup" [ngSwitch]="entityFilterFormGroup.get('type').value">
<ng-template [ngSwitchCase]="aliasFilterType.singleEntity"> <ng-template [ngSwitchCase]="aliasFilterType.singleEntity">
<tb-entity-select required <tb-entity-select required addQueueStats
useAliasEntityTypes="true" useAliasEntityTypes="true"
formControlName="singleEntity"> formControlName="singleEntity">
</tb-entity-select> </tb-entity-select>
@ -37,6 +37,7 @@
<ng-template [ngSwitchCase]="aliasFilterType.entityList"> <ng-template [ngSwitchCase]="aliasFilterType.entityList">
<tb-entity-type-select required <tb-entity-type-select required
showLabel showLabel
addQueueStats
[allowedEntityTypes]="allowedEntityTypes" [allowedEntityTypes]="allowedEntityTypes"
formControlName="entityType"> formControlName="entityType">
</tb-entity-type-select> </tb-entity-type-select>
@ -49,6 +50,7 @@
<ng-template [ngSwitchCase]="aliasFilterType.entityName"> <ng-template [ngSwitchCase]="aliasFilterType.entityName">
<tb-entity-type-select required <tb-entity-type-select required
showLabel showLabel
addQueueStats
[allowedEntityTypes]="allowedEntityTypes" [allowedEntityTypes]="allowedEntityTypes"
formControlName="entityType"> formControlName="entityType">
</tb-entity-type-select> </tb-entity-type-select>
@ -65,6 +67,7 @@
<ng-template [ngSwitchCase]="aliasFilterType.entityType"> <ng-template [ngSwitchCase]="aliasFilterType.entityType">
<tb-entity-type-select required <tb-entity-type-select required
showLabel showLabel
addQueueStats
[allowedEntityTypes]="allowedEntityTypes" [allowedEntityTypes]="allowedEntityTypes"
formControlName="entityType"> formControlName="entityType">
</tb-entity-type-select> </tb-entity-type-select>

17
ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts

@ -40,6 +40,7 @@ import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum'; import { Authority } from '@shared/models/authority.enum';
import { getEntityDetailsPageURL, isDefinedAndNotNull, isEqual } from '@core/utils'; import { getEntityDetailsPageURL, isDefinedAndNotNull, isEqual } from '@core/utils';
import { coerceBoolean } from '@shared/decorators/coercion'; import { coerceBoolean } from '@shared/decorators/coercion';
import { QueueStatisticsInfo } from '@shared/models/queue.models';
@Component({ @Component({
selector: 'tb-entity-autocomplete', selector: 'tb-entity-autocomplete',
@ -185,7 +186,9 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
} }
}), }),
// startWith<string | BaseData<EntityId>>(''), // startWith<string | BaseData<EntityId>>(''),
map(value => value ? (typeof value === 'string' ? value : value.name) : ''), map(value =>
value ? (typeof value === 'string' ? value : value.name) : ''
),
switchMap(name => this.fetchEntities(name)), switchMap(name => this.fetchEntities(name)),
share() share()
) )
@ -249,6 +252,11 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
this.noEntitiesMatchingText = 'alarm.no-alarms-matching'; this.noEntitiesMatchingText = 'alarm.no-alarms-matching';
this.entityRequiredText = 'alarm.alarm-required'; this.entityRequiredText = 'alarm.alarm-required';
break; break;
case EntityType.QUEUE_STATS:
this.entityText = 'queue-statistics.queue-statistics';
this.noEntitiesMatchingText = 'queue-statistics.no-queue-statistics-matching';
this.entityRequiredText = 'queue-statistics.queue-statistics-required';
break;
case AliasEntityType.CURRENT_CUSTOMER: case AliasEntityType.CURRENT_CUSTOMER:
this.entityText = 'customer.default-customer'; this.entityText = 'customer.default-customer';
this.noEntitiesMatchingText = 'customer.no-customers-matching'; this.noEntitiesMatchingText = 'customer.no-customers-matching';
@ -313,6 +321,10 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
} catch (e) { } catch (e) {
this.propagateChange(null); this.propagateChange(null);
} }
if (this.entityTypeValue === EntityType.QUEUE_STATS && isDefinedAndNotNull(entity)) {
const queueStat = entity as QueueStatisticsInfo;
entity.name = `${queueStat.queueName} (${queueStat.serviceId})`;
}
this.modelValue = entity !== null ? (this.useFullEntityId ? entity.id : entity.id.id) : null; this.modelValue = entity !== null ? (this.useFullEntityId ? entity.id : entity.id.id) : null;
this.entityURL = getEntityDetailsPageURL(this.modelValue as string, targetEntityType); this.entityURL = getEntityDetailsPageURL(this.modelValue as string, targetEntityType);
this.selectEntityFormGroup.get('entity').patchValue(entity !== null ? entity : '', {emitEvent: false}); this.selectEntityFormGroup.get('entity').patchValue(entity !== null ? entity : '', {emitEvent: false});
@ -361,6 +373,9 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
data.forEach(entity => !excludeEntityIdsSet.has(entity.id.id) && entities.push(entity)); data.forEach(entity => !excludeEntityIdsSet.has(entity.id.id) && entities.push(entity));
return entities; return entities;
} else { } else {
if (this.entityTypeValue === EntityType.QUEUE_STATS) {
data.forEach((entity: QueueStatisticsInfo) => entity.name = `${entity.queueName} (${entity.serviceId})`);
}
return data; return data;
} }
} else { } else {

22
ui-ngx/src/app/shared/components/entity/entity-list.component.ts

@ -25,7 +25,13 @@ import {
SimpleChanges, SimpleChanges,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormGroup,
Validators
} from '@angular/forms';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { filter, map, mergeMap, share, tap } from 'rxjs/operators'; import { filter, map, mergeMap, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@ -39,6 +45,7 @@ import { MatAutocomplete } from '@angular/material/autocomplete';
import { MatChipGrid } from '@angular/material/chips'; import { MatChipGrid } from '@angular/material/chips';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { SubscriptSizing } from '@angular/material/form-field'; import { SubscriptSizing } from '@angular/material/form-field';
import { QueueStatisticsInfo } from '@shared/models/queue.models';
@Component({ @Component({
selector: 'tb-entity-list', selector: 'tb-entity-list',
@ -178,6 +185,9 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
this.entityService.getEntities(this.entityType, value).subscribe( this.entityService.getEntities(this.entityType, value).subscribe(
(entities) => { (entities) => {
this.entities = entities; this.entities = entities;
if (this.entityType === EntityType.QUEUE_STATS) {
this.entities.forEach((queueStat: QueueStatisticsInfo) => queueStat.name = `${queueStat.queueName} (${queueStat.serviceId})`);
}
this.entityListFormGroup.get('entities').setValue(this.entities); this.entityListFormGroup.get('entities').setValue(this.entities);
} }
); );
@ -238,7 +248,15 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
return this.entityService.getEntitiesByNameFilter(this.entityType, searchText, return this.entityService.getEntitiesByNameFilter(this.entityType, searchText,
50, this.subType ? this.subType : '', {ignoreLoading: true}).pipe( 50, this.subType ? this.subType : '', {ignoreLoading: true}).pipe(
map((data) => data ? data : [])); map((data) => {
if (data) {
if (this.entityType === EntityType.QUEUE_STATS) {
data.forEach((entity: QueueStatisticsInfo) => entity.name = `${entity.queueName} (${entity.serviceId})`);
}
return data;
}
return [];
}));
} }
onFocus() { onFocus() {

1
ui-ngx/src/app/shared/components/entity/entity-select.component.html

@ -22,6 +22,7 @@
[required]="required" [required]="required"
[useAliasEntityTypes]="useAliasEntityTypes" [useAliasEntityTypes]="useAliasEntityTypes"
[allowedEntityTypes]="allowedEntityTypes" [allowedEntityTypes]="allowedEntityTypes"
[addQueueStats]="addQueueStats"
formControlName="entityType"> formControlName="entityType">
</tb-entity-type-select> </tb-entity-type-select>
<tb-entity-autocomplete <tb-entity-autocomplete

5
ui-ngx/src/app/shared/components/entity/entity-select.component.ts

@ -24,6 +24,7 @@ import { EntityService } from '@core/http/entity.service';
import { EntityId } from '@shared/models/id/entity-id'; import { EntityId } from '@shared/models/id/entity-id';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
import { coerceBoolean } from '@shared/decorators/coercion';
@Component({ @Component({
selector: 'tb-entity-select', selector: 'tb-entity-select',
@ -59,6 +60,10 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte
@Input() @Input()
disabled: boolean; disabled: boolean;
@Input()
@coerceBoolean()
addQueueStats = false;
displayEntityTypeSelect: boolean; displayEntityTypeSelect: boolean;
AliasEntityType = AliasEntityType; AliasEntityType = AliasEntityType;

8
ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts

@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core';
import { AliasEntityType, EntityType, entityTypeTranslations } from '@app/shared/models/entity-type.models'; import { AliasEntityType, EntityType, entityTypeTranslations } from '@app/shared/models/entity-type.models';
import { EntityService } from '@core/http/entity.service'; import { EntityService } from '@core/http/entity.service';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { coerceBoolean } from '@shared/decorators/coercion';
@Component({ @Component({
selector: 'tb-entity-type-select', selector: 'tb-entity-type-select',
@ -48,6 +49,10 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit,
@Input() @Input()
filterAllowedEntityTypes = true; filterAllowedEntityTypes = true;
@Input()
@coerceBoolean()
addQueueStats = false;
private showLabelValue: boolean; private showLabelValue: boolean;
get showLabel(): boolean { get showLabel(): boolean {
return this.showLabelValue; return this.showLabelValue;
@ -91,7 +96,8 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit,
ngOnInit() { ngOnInit() {
this.entityTypes = this.filterAllowedEntityTypes ? this.entityTypes = this.filterAllowedEntityTypes ?
this.entityService.prepareAllowedEntityTypesList(this.allowedEntityTypes, this.useAliasEntityTypes) : this.allowedEntityTypes; this.entityService.prepareAllowedEntityTypesList(this.allowedEntityTypes, this.useAliasEntityTypes, this.addQueueStats) :
this.allowedEntityTypes;
this.entityTypeFormGroup.get('entityType').valueChanges.subscribe( this.entityTypeFormGroup.get('entityType').valueChanges.subscribe(
(value) => { (value) => {
let modelValue; let modelValue;

6
ui-ngx/src/app/shared/models/entity-type.models.ts

@ -367,7 +367,11 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
EntityType.QUEUE_STATS, EntityType.QUEUE_STATS,
{ {
type: 'entity.type-queue-stats', type: 'entity.type-queue-stats',
typePlural: 'entity.type-queues-stats' typePlural: 'entity.type-queues-stats',
list: 'queue-statistics.list-of-queue-statistics',
noEntities: 'queue-statistics.no-queue-statistics-text',
selectedEntities: 'queue-statistics.selected-queue-statistics',
nameStartsWith: 'queue-statistics.queue-statistics-starts-with',
} }
], ],
[ [

6
ui-ngx/src/app/shared/models/queue.models.ts

@ -126,3 +126,9 @@ export interface QueueInfo extends BaseData<QueueId>, HasTenantId {
duplicateMsgToAllPartitions?: boolean; duplicateMsgToAllPartitions?: boolean;
}; };
} }
export interface QueueStatisticsInfo extends BaseData<QueueId>, HasTenantId {
queueName: string;
serviceId: string;
name?: string;
}

9
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -4322,6 +4322,15 @@
"retry-failed-and-timeout-hint": "Retry all failed and timed-out messages from processing pack" "retry-failed-and-timeout-hint": "Retry all failed and timed-out messages from processing pack"
} }
}, },
"queue-statistics": {
"queue-statistics": "Queue statistics",
"no-queue-statistics-matching": "No queue statistics matching '{{entity}}' were found.",
"queue-statistics-required": "Queue statistics is required.",
"list-of-queue-statistics": "{ count, plural, =1 {One queue statistic} other {List of # queue statistics} }",
"selected-queue-statistics": "{ count, plural, =1 {1 queue statistic} other {# queue statistics} } selected",
"no-queue-statistics-text": "No queue statistics found",
"queue-statistics-starts-with": "Queue statistics whose names start with '{{prefix}}'"
},
"server-error": { "server-error": {
"general": "General server error", "general": "General server error",
"authentication": "Authentication error", "authentication": "Authentication error",

Loading…
Cancel
Save