Browse Source

UI: add queues to tenant profile

pull/6134/head
fe-dev 4 years ago
parent
commit
aba3974a77
  1. 4
      ui-ngx/src/app/modules/common/modules-map.ts
  2. 10
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  3. 4
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts
  4. 194
      ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html
  5. 22
      ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss
  6. 206
      ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts
  7. 42
      ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html
  8. 31
      ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss
  9. 178
      ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts
  10. 5
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html
  11. 2
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.ts
  12. 24
      ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html
  13. 10
      ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss
  14. 78
      ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts
  15. 204
      ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html
  16. 43
      ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss
  17. 6
      ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts
  18. 7
      ui-ngx/src/app/shared/models/queue.models.ts
  19. 4
      ui-ngx/src/app/shared/models/tenant.model.ts
  20. 5
      ui-ngx/src/assets/locale/locale.constant-en_US.json

4
ui-ngx/src/app/modules/common/modules-map.ts

@ -287,6 +287,8 @@ import * as DisplayWidgetTypesPanelComponent from '@home/components/dashboard-pa
import * as AlarmDurationPredicateValueComponent from '@home/components/profile/alarm/alarm-duration-predicate-value.component';
import * as DashboardImageDialogComponent from '@home/components/dashboard-page/dashboard-image-dialog.component';
import * as WidgetContainerComponent from '@home/components/widget/widget-container.component';
import * as TenantProfileQueuesComponent from '@home/components/profile/queue/tenant-profile-queues.component';
import { TenantProfileQueueComponent } from '@home/components/profile/queue/tenant-profile-queue.component';
import { IModulesMap } from '@modules/common/modules-map.models';
@ -570,6 +572,8 @@ class ModulesMap implements IModulesMap {
'@home/components/profile/alarm/alarm-duration-predicate-value.component': AlarmDurationPredicateValueComponent,
'@home/components/dashboard-page/dashboard-image-dialog.component': DashboardImageDialogComponent,
'@home/components/widget/widget-container.component': WidgetContainerComponent,
'@home/components/profile/queue/tenant-profile-queues.component': TenantProfileQueuesComponent,
'@home/components/profile/queue/tenant-profile-queue.component': TenantProfileQueueComponent
};
init() {

10
ui-ngx/src/app/modules/home/components/home-components.module.ts

@ -148,6 +148,8 @@ import {
} from '@home/components/tokens';
import { DashboardStateComponent } from '@home/components/dashboard-page/dashboard-state.component';
import { EntityDetailsPageComponent } from '@home/components/entity/entity-details-page.component';
import { TenantProfileQueuesComponent } from '@home/components/profile/queue/tenant-profile-queues.component';
import { TenantProfileQueueComponent } from '@home/components/profile/queue/tenant-profile-queue.component';
@NgModule({
declarations:
@ -267,7 +269,9 @@ import { EntityDetailsPageComponent } from '@home/components/entity/entity-detai
DashboardStateDialogComponent,
DashboardImageDialogComponent,
EmbedDashboardDialogComponent,
DisplayWidgetTypesPanelComponent
DisplayWidgetTypesPanelComponent,
TenantProfileQueuesComponent,
TenantProfileQueueComponent
],
imports: [
CommonModule,
@ -380,7 +384,9 @@ import { EntityDetailsPageComponent } from '@home/components/entity/entity-detai
DashboardStateDialogComponent,
DashboardImageDialogComponent,
EmbedDashboardDialogComponent,
DisplayWidgetTypesPanelComponent
DisplayWidgetTypesPanelComponent,
TenantProfileQueuesComponent,
TenantProfileQueueComponent
],
providers: [
WidgetComponentService,

4
ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts

@ -42,7 +42,7 @@ import { ServiceType } from '@shared/models/queue.models';
import { EntityId } from '@shared/models/id/entity-id';
import { OtaUpdateType } from '@shared/models/ota-package.models';
import { DashboardId } from '@shared/models/id/dashboard-id';
import { QueueId } from "@shared/models/id/queue-id";
import { QueueId } from '@shared/models/id/queue-id';
@Component({
selector: 'tb-device-profile',
@ -198,7 +198,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
}}, {emitEvent: false});
this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false});
this.entityForm.patchValue({defaultDashboardId: entity.defaultDashboardId ? entity.defaultDashboardId.id : null}, {emitEvent: false});
this.entityForm.patchValue({defaultQueueId: entity.defaultQueueId ? entity.defaultQueueId.id: null}, {emitEvent: false});
this.entityForm.patchValue({defaultQueueId: entity.defaultQueueId ? entity.defaultQueueId.id : null}, {emitEvent: false});
this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false});
this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false});
this.entityForm.patchValue({description: entity.description}, {emitEvent: false});

194
ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html

@ -0,0 +1,194 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mat-expansion-panel fxFlex [formGroup]="queueFormGroup" [(expanded)]="expanded">
<mat-expansion-panel-header>
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<mat-panel-title>
<div fxLayout="row" fxFlex fxLayoutAlign="start center">
{{ queueTitle }}
</div>
</mat-panel-title>
<span fxFlex></span>
<button *ngIf="!mainQueue && !disabled" mat-icon-button style="min-width: 40px;"
type="button"
(click)="removeQueue.emit()"
matTooltip="{{ 'action.remove' | translate }}"
matTooltipPosition="above">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="column" fxLayoutGap="0.5em">
<mat-divider></mat-divider>
<mat-form-field class="mat-block">
<mat-label translate>admin.queue-name</mat-label>
<input matInput formControlName="name" required>
<mat-error *ngIf="queueFormGroup.get('name').hasError('required')">
{{ 'queue.name-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.poll-interval</mat-label>
<input type="number" matInput formControlName="pollInterval" required>
<mat-error *ngIf="queueFormGroup.get('pollInterval').hasError('required')">
{{ 'queue.poll-interval-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('pollInterval').hasError('min') &&
!queueFormGroup.get('pollInterval').hasError('required')">
{{ 'queue.poll-interval-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.partitions</mat-label>
<input type="number" matInput formControlName="partitions" required>
<mat-error *ngIf="queueFormGroup.get('partitions').hasError('required')">
{{ 'queue.partitions-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('partitions').hasError('min') &&
!queueFormGroup.get('partitions').hasError('required')">
{{ 'queue.partitions-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-checkbox class="hinted-checkbox" formControlName="consumerPerPartition">
<div>{{ 'queue.consumer-per-partition' | translate }}</div>
<div class="tb-hint">{{'queue.consumer-per-partition-hint' | translate}}</div>
</mat-checkbox>
<mat-form-field class="mat-block">
<mat-label translate>queue.processing-timeout</mat-label>
<input type="number" matInput formControlName="packProcessingTimeout" required>
<mat-error *ngIf="queueFormGroup.get('packProcessingTimeout').hasError('required')">
{{ 'queue.pack-processing-timeout-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('packProcessingTimeout').hasError('min') &&
!queueFormGroup.get('packProcessingTimeout').hasError('required')">
{{ 'queue.pack-processing-timeout-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-accordion class="queue-strategy" [multi]="true">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title translate>
queue.submit-strategy
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div formGroupName="submitStrategy">
<mat-form-field class="mat-block">
<mat-label translate>queue.submit-strategy</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let strategy of submitStrategies" [value]="strategy">
{{ strategy }}
</mat-option>
</mat-select>
<mat-error *ngIf="queueFormGroup.get('submitStrategy.type').hasError('required')">
{{ 'queue.submit-strategy-type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block" *ngIf="hideBatchSize">
<mat-label translate>queue.batch-size</mat-label>
<input type="number" matInput formControlName="batchSize" required>
<mat-error *ngIf="queueFormGroup.get('submitStrategy.batchSize').hasError('required')">
{{ 'queue.batch-size-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('submitStrategy.batchSize').hasError('min') &&
!queueFormGroup.get('submitStrategy.batchSize').hasError('required')">
{{ 'queue.batch-size-min-value' | translate }}
</mat-error>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title translate>
queue.processing-strategy
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div formGroupName="processingStrategy">
<mat-form-field class="mat-block">
<mat-label translate>queue.processing-strategy</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let strategy of processingStrategies" [value]="strategy">
{{ strategy }}
</mat-option>
</mat-select>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.type').hasError('required')">
{{ 'queue.processing-strategy-type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.retries</mat-label>
<input type="number" matInput formControlName="retries" required>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.retries').hasError('required')">
{{ 'queue.retries-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.retries').hasError('min') &&
!queueFormGroup.get('processingStrategy.retries').hasError('required')">
{{ 'queue.retries-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.failure-percentage</mat-label>
<input type="number" matInput formControlName="failurePercentage" required>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.failurePercentage').hasError('required')">
{{ 'queue.failure-percentage-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.failurePercentage').hasError('min') &&
!queueFormGroup.get('processingStrategy.failurePercentage').hasError('required') &&
!queueFormGroup.get('processingStrategy.failurePercentage').hasError('max')">
{{ 'queue.failure-percentage-min-value' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.failurePercentage').hasError('max') &&
!queueFormGroup.get('processingStrategy.failurePercentage').hasError('required') &&
!queueFormGroup.get('processingStrategy.failurePercentage').hasError('min')">
{{ 'queue.failure-percentage-max-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.pause-between-retries</mat-label>
<input type="number" matInput formControlName="pauseBetweenRetries" required>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.pauseBetweenRetries').hasError('required')">
{{ 'queue.pause-between-retries-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.pauseBetweenRetries').hasError('min') &&
!queueFormGroup.get('processingStrategy.pauseBetweenRetries').hasError('required')">
{{ 'queue.pause-between-retries-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.max-pause-between-retries</mat-label>
<input type="number" matInput formControlName="maxPauseBetweenRetries" required>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.maxPauseBetweenRetries').hasError('required')">
{{ 'queue.max-pause-between-retries-required' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('processingStrategy.maxPauseBetweenRetries').hasError('min') &&
!queueFormGroup.get('processingStrategy.maxPauseBetweenRetries').hasError('required')">
{{ 'queue.max-pause-between-retries-min-value' | translate }}
</mat-error>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
</div>
</ng-template>
</mat-expansion-panel>

22
ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss

@ -0,0 +1,22 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host ::ng-deep {
.queue-strategy {
.mat-expansion-panel-body {
padding-bottom: 0 !important;
}
}
}

206
ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts

@ -0,0 +1,206 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
import {
ControlValueAccessor,
FormBuilder,
FormControl,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
Validator,
Validators
} from '@angular/forms';
import { DeviceProfileAlarm } from '@shared/models/device.models';
import { MatDialog } from '@angular/material/dialog';
import { UtilsService } from '@core/services/utils.service';
import { QueueProcessingStrategyTypes, QueueSubmitStrategyTypes } from '@shared/models/queue.models';
@Component({
selector: 'tb-tenant-profile-queue',
templateUrl: './tenant-profile-queue.component.html',
styleUrls: ['./tenant-profile-queue.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TenantProfileQueueComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => TenantProfileQueueComponent),
multi: true,
}
]
})
export class TenantProfileQueueComponent implements ControlValueAccessor, OnInit, Validator {
@Input()
disabled: boolean;
@Output()
removeQueue = new EventEmitter();
@Input()
expanded = false;
@Input()
mainQueue = false;
@Input()
newQueue = false;
private modelValue: DeviceProfileAlarm;
queueFormGroup: FormGroup;
submitStrategies: string[] = [];
processingStrategies: string[] = [];
hideBatchSize = false;
private propagateChange = null;
private propagateChangePending = false;
constructor(private dialog: MatDialog,
private utils: UtilsService,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
if (this.propagateChangePending) {
this.propagateChangePending = false;
setTimeout(() => {
this.propagateChange(this.modelValue);
}, 0);
}
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.submitStrategies = Object.values(QueueSubmitStrategyTypes);
this.processingStrategies = Object.values(QueueProcessingStrategyTypes);
this.queueFormGroup = this.fb.group(
{
name: ['', [Validators.required]],
pollInterval: [25, [Validators.min(1), Validators.required]],
partitions: [10, [Validators.min(1), Validators.required]],
consumerPerPartition: [false, []],
packProcessingTimeout: [2000, [Validators.min(1), Validators.required]],
submitStrategy: this.fb.group({
type: [null, [Validators.required]],
batchSize: [0, [Validators.min(1), Validators.required]],
}),
processingStrategy: this.fb.group({
type: [null, [Validators.required]],
retries: [3, [Validators.min(0), Validators.required]],
failurePercentage: [ 0, [Validators.min(0), Validators.required, Validators.max(100)]],
pauseBetweenRetries: [3, [Validators.min(1), Validators.required]],
maxPauseBetweenRetries: [3, [Validators.min(1), Validators.required]],
}),
topic: ['']
});
this.queueFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
this.queueFormGroup.get('name').valueChanges.subscribe((value) => this.queueFormGroup.patchValue({topic: `tb_rule_engine.${value}`}));
this.queueFormGroup.get('submitStrategy').get('type').valueChanges.subscribe(() => {
this.submitStrategyTypeChanged();
});
if (this.newQueue) {
this.queueFormGroup.get('name').enable({emitEvent: false});
} else {
this.queueFormGroup.get('name').disable({emitEvent: false});
}
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.queueFormGroup.disable({emitEvent: false});
} else {
this.queueFormGroup.enable({emitEvent: false});
this.queueFormGroup.get('name').disable({emitEvent: false});
}
}
writeValue(value: DeviceProfileAlarm): void {
this.propagateChangePending = false;
this.modelValue = value;
if (!this.modelValue.alarmType) {
this.expanded = true;
}
this.queueFormGroup.reset(this.modelValue || undefined, {emitEvent: false});
if (!this.disabled && !this.queueFormGroup.valid) {
this.updateModel();
}
}
public validate(c: FormControl) {
if (c.parent) {
const queueName = c.value.name;
const profileQueues = [];
c.parent.getRawValue().forEach((queue) => {
profileQueues.push(queue.name);
}
);
if (profileQueues.filter(profileQueue => profileQueue === queueName).length > 1) {
this.queueFormGroup.get('name').setErrors({
unique: true
});
}
}
return (this.queueFormGroup.valid) ? null : {
queue: {
valid: false,
},
};
}
get queueTitle(): string {
const queueName = this.queueFormGroup.get('name').value;
return this.utils.customTranslation(queueName, queueName);
}
private updateModel() {
const value = this.queueFormGroup.value;
this.modelValue = {...this.modelValue, ...value};
if (this.propagateChange) {
this.propagateChange(this.modelValue);
} else {
this.propagateChangePending = true;
}
}
submitStrategyTypeChanged() {
const form = this.queueFormGroup.get('submitStrategy') as FormGroup;
const type: QueueSubmitStrategyTypes = form.get('type').value;
const batchSizeField = form.get('batchSize');
if (type === QueueSubmitStrategyTypes.BATCH) {
batchSizeField.enable();
batchSizeField.patchValue(1000);
this.hideBatchSize = true;
} else {
batchSizeField.patchValue(null);
batchSizeField.disable();
this.hideBatchSize = false;
}
}
}

42
ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html

@ -0,0 +1,42 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div fxLayout="column">
<div class="tb-tenant-profile-queues">
<mat-accordion [multi]="true">
<div *ngFor="let queuesControl of queuesFormArray().controls; trackBy: trackByQueue;
let $index = index; last as isLast;" fxLayout="column">
<tb-tenant-profile-queue [formControl]="queuesControl"
[mainQueue]="$index === 0"
[newQueue]="newQueue"
(removeQueue)="removeQueue($index)">
</tb-tenant-profile-queue>
</div>
</mat-accordion>
</div>
<div *ngIf="!queuesFormArray().controls.length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">tenant-profile.no-queue</span>
</div>
<div *ngIf="!disabled" style="padding-top: 16px;">
<button mat-raised-button color="primary"
type="button"
(click)="addQueue()">
<span translate>tenant-profile.add-queue</span>
</button>
</div>
</div>

31
ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss

@ -0,0 +1,31 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import '../../../../../../scss/constants';
:host {
.tb-tenant-profile-queues {
&.mat-padding {
padding: 8px;
@media #{$mat-gt-sm} {
padding: 16px;
}
}
}
.tb-prompt{
margin: 30px 0;
}
}

178
ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts

@ -0,0 +1,178 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
FormArray,
FormBuilder,
FormControl,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
Validator,
Validators
} from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Subscription } from 'rxjs';
import { QueueInfo } from '@shared/models/queue.models';
@Component({
selector: 'tb-tenant-profile-queues',
templateUrl: './tenant-profile-queues.component.html',
styleUrls: ['./tenant-profile-queues.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TenantProfileQueuesComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => TenantProfileQueuesComponent),
multi: true,
}
]
})
export class TenantProfileQueuesComponent implements ControlValueAccessor, OnInit, Validator {
tenantProfileQueuesFormGroup: FormGroup;
newQueue = false;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@Input()
disabled: boolean;
private valueChangeSubscription: Subscription = null;
private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.tenantProfileQueuesFormGroup = this.fb.group({
queues: this.fb.array([])
});
}
queuesFormArray(): FormArray {
return this.tenantProfileQueuesFormGroup.get('queues') as FormArray;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.tenantProfileQueuesFormGroup.disable({emitEvent: false});
} else {
this.tenantProfileQueuesFormGroup.enable({emitEvent: false});
}
}
writeValue(queues: Array<QueueInfo> | null): void {
if (this.valueChangeSubscription) {
this.valueChangeSubscription.unsubscribe();
}
const queuesControls: Array<AbstractControl> = [];
if (queues) {
queues.forEach((queue) => {
queuesControls.push(this.fb.control(queue, [Validators.required]));
});
}
this.tenantProfileQueuesFormGroup.setControl('queues', this.fb.array(queuesControls));
if (this.disabled) {
this.tenantProfileQueuesFormGroup.disable({emitEvent: false});
} else {
this.tenantProfileQueuesFormGroup.enable({emitEvent: false});
}
this.valueChangeSubscription = this.tenantProfileQueuesFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
public trackByQueue(index: number, queueControl: AbstractControl): string {
if (queueControl) {
return queueControl.value.id;
} else {
return null;
}
}
public removeQueue(index: number) {
(this.tenantProfileQueuesFormGroup.get('queues') as FormArray).removeAt(index);
}
public addQueue() {
const queue = {
consumerPerPartition: false,
name: '',
packProcessingTimeout: 2000,
partitions: 10,
pollInterval: 25,
processingStrategy: {
failurePercentage: 0,
maxPauseBetweenRetries: 3,
pauseBetweenRetries: 3,
retries: 3,
type: ''
},
submitStrategy: {
batchSize: 0,
type: ''
},
topic: ''
};
this.newQueue = true;
const queuesArray = this.tenantProfileQueuesFormGroup.get('queues') as FormArray;
queuesArray.push(this.fb.control(queue, []));
this.tenantProfileQueuesFormGroup.updateValueAndValidity();
if (!this.tenantProfileQueuesFormGroup.valid) {
this.updateModel();
}
}
public validate(c: FormControl) {
return (this.tenantProfileQueuesFormGroup.valid) ? null : {
queues: {
valid: false,
},
};
}
private updateModel() {
const queues: Array<QueueInfo> = this.tenantProfileQueuesFormGroup.get('queues').value;
this.propagateChange(queues);
}
}

5
ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html

@ -16,11 +16,6 @@
-->
<form [formGroup]="tenantProfileDataFormGroup" style="padding-bottom: 16px;">
<!-- <tb-json-object-edit *ngIf="isolatedTbRuleEngine"-->
<!-- formControlName="queueConfiguration"-->
<!-- label="{{ 'admin.queue-configuration' | translate }}">-->
<!-- </tb-json-object-edit>-->
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>

2
ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.ts

@ -79,7 +79,7 @@ export class TenantProfileDataComponent implements ControlValueAccessor, OnInit
}
writeValue(value: TenantProfileData | null): void {
this.tenantProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false});
this.tenantProfileDataFormGroup.patchValue({configuration: value}, {emitEvent: false});
}
private updateModel() {

24
ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html

@ -68,10 +68,26 @@
<div class="tb-hint">{{'tenant.isolated-tb-rule-engine-details' | translate}}</div>
</mat-checkbox>
</div>
<tb-tenant-profile-data
formControlName="profileData"
required>
</tb-tenant-profile-data>
<mat-accordion formGroupName="profileData">
<mat-expansion-panel [expanded]="true" *ngIf="entityForm.get('isolatedTbRuleEngine').value">
<mat-expansion-panel-header>
<mat-panel-title>
<div>{{'tenant-profile.queues-with-count' | translate:
{count: entityForm.get('profileData').get('queueConfiguration').value ?
entityForm.get('profileData').get('queueConfiguration').value.length : 0} }}</div>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-tenant-profile-queues
formControlName="queueConfiguration"
></tb-tenant-profile-queues>
</ng-template>
</mat-expansion-panel>
<tb-tenant-profile-data
formControlName="configuration"
required>
</tb-tenant-profile-data>
</mat-accordion>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.description</mat-label>
<textarea matInput formControlName="description" rows="2"></textarea>

10
ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss

@ -25,4 +25,14 @@
white-space: normal;
}
}
.fields-group {
padding: 0 16px 8px;
margin-bottom: 10px;
border: 1px groove rgba(0, 0, 0, .25);
border-radius: 4px;
legend {
color: rgba(0, 0, 0, .7);
width: fit-content;
}
}
}

78
ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts

@ -18,12 +18,7 @@ import { ChangeDetectorRef, Component, Inject, Input, Optional } from '@angular/
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import {
createTenantProfileConfiguration,
TenantProfile,
TenantProfileData,
TenantProfileType
} from '@shared/models/tenant.model';
import { createTenantProfileConfiguration, TenantProfile, TenantProfileType } from '@shared/models/tenant.model';
import { ActionNotificationShow } from '@app/core/notification/notification.actions';
import { TranslateService } from '@ngx-translate/core';
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
@ -48,11 +43,6 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
super(store, fb, entityValue, entitiesTableConfigValue, cd);
}
ngOnInit() {
this.showQueueParams();
this.entityForm.get('isolatedTbRuleEngine').valueChanges.subscribe(() => this.showQueueParams());
}
hideDelete() {
if (this.entitiesTableConfig) {
return !this.entitiesTableConfig.deleteEnabled(this.entity);
@ -62,37 +52,61 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
}
buildForm(entity: TenantProfile): FormGroup {
return this.fb.group(
const mainQueue = [
{
consumerPerPartition: true,
name: 'Main',
packProcessingTimeout: 2000,
partitions: 10,
pollInterval: 25,
processingStrategy: {
failurePercentage: 0,
maxPauseBetweenRetries: 3,
pauseBetweenRetries: 3,
retries: 3,
type: 'SKIP_ALL_FAILURES'
},
submitStrategy: {
batchSize: 1000,
type: 'BURST'
},
topic: 'tb_rule_engine.main'
}
];
const formGroup = this.fb.group(
{
name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
isolatedTbCore: [entity ? entity.isolatedTbCore : false, []],
isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []],
profileData: [entity && !this.isAdd ? entity.profileData : {
configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT)
} as TenantProfileData, []],
profileData: this.fb.group({
configuration: [entity && !this.isAdd ? entity?.profileData.configuration
: createTenantProfileConfiguration(TenantProfileType.DEFAULT), []],
queueConfiguration: [null, []]
}),
description: [entity ? entity.description : '', []],
}
);
formGroup.get('isolatedTbRuleEngine').valueChanges.subscribe((value) => {
if (value) {
formGroup.get('profileData').patchValue({
queueConfiguration: mainQueue
}, {emitEvent: false});
} else {
formGroup.get('profileData').patchValue({
queueConfiguration: null
}, {emitEvent: false});
}
});
return formGroup;
}
updateForm(entity: TenantProfile) {
this.entityForm.patchValue({name: entity.name});
this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore});
this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine});
this.entityForm.patchValue({profileData: !this.isAdd ? entity.profileData : {
configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT)
} as TenantProfileData});
this.entityForm.patchValue({description: entity.description});
}
showQueueParams(): boolean {
let isolatedTbRuleEngine: boolean = this.entityForm.get('isolatedTbRuleEngine').value;
if (isolatedTbRuleEngine) {
//enable
} else {
//disable
}
return isolatedTbRuleEngine;
this.entityForm.patchValue({name: entity.name}, {emitEvent: false});
this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore}, {emitEvent: false});
this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}, {emitEvent: false});
this.entityForm.get('profileData').patchValue({configuration: entity.profileData?.configuration}, {emitEvent: false});
this.entityForm.get('profileData').patchValue({queueConfiguration: entity.profileData?.queueConfiguration}, {emitEvent: false});
this.entityForm.patchValue({description: entity.description}, {emitEvent: false});
}
updateFormState() {

204
ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html

@ -20,12 +20,12 @@
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"
[fxShow]="!hideDelete() && !isEdit">
{{'queue.delete' | translate }}
{{ 'queue.delete' | translate }}
</button>
</div>
<div class="mat-padding" fxLayout="column">
<form [formGroup]="entityForm">
<form [formGroup]="entityForm" class="queue-form">
<fieldset [disabled]="(isLoading$ | async) || !isEdit">
<mat-form-field class="mat-block">
<mat-label translate>admin.queue-name</mat-label>
@ -57,10 +57,6 @@
</mat-error>
</mat-form-field>
<!-- <tb-checkbox formControlName="consumerPerPartition" style="display: block; padding-bottom: 16px;">-->
<!-- {{ 'queue.consumer-per-partition' | translate }}-->
<!-- </tb-checkbox>-->
<mat-checkbox class="hinted-checkbox" formControlName="consumerPerPartition">
<div>{{ 'queue.consumer-per-partition' | translate }}</div>
<div class="tb-hint">{{'queue.consumer-per-partition-hint' | translate}}</div>
@ -77,115 +73,113 @@
{{ 'queue.pack-processing-timeout-min-value' | translate }}
</mat-error>
</mat-form-field>
<div class="mat-accordion-container">
<mat-accordion [multi]="true">
<mat-expansion-panel #panel1 hideToggle>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<mat-label translate>queue.submit-strategy</mat-label>
<mat-icon>{{panel1.expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}</mat-icon>
<mat-panel-title translate>
queue.submit-strategy
</mat-panel-title>
</mat-expansion-panel-header>
<div formGroupName="submitStrategy">
<mat-form-field class="mat-block">
<mat-label translate>queue.submit-strategy</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let strategy of submitStrategies" [value]="strategy">
{{ strategy }}
</mat-option>
</mat-select>
<mat-error *ngIf="entityForm.get('submitStrategy.type').hasError('required')">
{{ 'queue.submit-strategy-type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block" *ngIf="hideBatchSize">
<mat-label translate>queue.batch-size</mat-label>
<input type="number" matInput formControlName="batchSize" required>
<mat-error *ngIf="entityForm.get('submitStrategy.batchSize').hasError('required')">
{{ 'queue.batch-size-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('submitStrategy.batchSize').hasError('min') &&
!entityForm.get('submitStrategy.batchSize').hasError('required')">
{{ 'queue.batch-size-min-value' | translate }}
</mat-error>
</mat-form-field>
</div>
<ng-template matExpansionPanelContent>
<div formGroupName="submitStrategy">
<mat-form-field class="mat-block">
<mat-label translate>queue.submit-strategy</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let strategy of submitStrategies" [value]="strategy">
{{ strategy }}
</mat-option>
</mat-select>
<mat-error *ngIf="entityForm.get('submitStrategy.type').hasError('required')">
{{ 'queue.submit-strategy-type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block" *ngIf="hideBatchSize">
<mat-label translate>queue.batch-size</mat-label>
<input type="number" matInput formControlName="batchSize" required>
<mat-error *ngIf="entityForm.get('submitStrategy.batchSize').hasError('required')">
{{ 'queue.batch-size-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('submitStrategy.batchSize').hasError('min') &&
!entityForm.get('submitStrategy.batchSize').hasError('required')">
{{ 'queue.batch-size-min-value' | translate }}
</mat-error>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
<mat-expansion-panel #panel2 hideToggle>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<mat-label translate>queue.processing-strategy</mat-label>
<mat-icon>{{panel2.expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}</mat-icon>
<mat-panel-title translate>
queue.processing-strategy
</mat-panel-title>
</mat-expansion-panel-header>
<div formGroupName="processingStrategy">
<mat-form-field class="mat-block">
<mat-label translate>queue.processing-strategy</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let strategy of processingStrategies" [value]="strategy">
{{ strategy }}
</mat-option>
</mat-select>
<mat-error *ngIf="entityForm.get('processingStrategy.type').hasError('required')">
{{ 'queue.processing-strategy-type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.retries</mat-label>
<input type="number" matInput formControlName="retries" required>
<mat-error *ngIf="entityForm.get('processingStrategy.retries').hasError('required')">
{{ 'queue.retries-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.retries').hasError('min') &&
!entityForm.get('processingStrategy.retries').hasError('required')">
{{ 'queue.retries-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.failure-percentage</mat-label>
<input type="number" matInput formControlName="failurePercentage" required>
<mat-error *ngIf="entityForm.get('processingStrategy.failurePercentage').hasError('required')">
{{ 'queue.failure-percentage-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.failurePercentage').hasError('min') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('required') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('max')">
{{ 'queue.failure-percentage-min-value' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.failurePercentage').hasError('max') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('required') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('min')">
{{ 'queue.failure-percentage-max-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.pause-between-retries</mat-label>
<input type="number" matInput formControlName="pauseBetweenRetries" required>
<mat-error *ngIf="entityForm.get('processingStrategy.pauseBetweenRetries').hasError('required')">
{{ 'queue.pause-between-retries-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.pauseBetweenRetries').hasError('min') &&
!entityForm.get('processingStrategy.pauseBetweenRetries').hasError('required')">
{{ 'queue.pause-between-retries-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.max-pause-between-retries</mat-label>
<input type="number" matInput formControlName="maxPauseBetweenRetries" required>
<mat-error *ngIf="entityForm.get('processingStrategy.maxPauseBetweenRetries').hasError('required')">
{{ 'queue.max-pause-between-retries-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.maxPauseBetweenRetries').hasError('min') &&
!entityForm.get('processingStrategy.maxPauseBetweenRetries').hasError('required')">
{{ 'queue.max-pause-between-retries-min-value' | translate }}
</mat-error>
</mat-form-field>
</div>
<ng-template matExpansionPanelContent>
<div formGroupName="processingStrategy">
<mat-form-field class="mat-block">
<mat-label translate>queue.processing-strategy</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let strategy of processingStrategies" [value]="strategy">
{{ strategy }}
</mat-option>
</mat-select>
<mat-error *ngIf="entityForm.get('processingStrategy.type').hasError('required')">
{{ 'queue.processing-strategy-type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.retries</mat-label>
<input type="number" matInput formControlName="retries" required>
<mat-error *ngIf="entityForm.get('processingStrategy.retries').hasError('required')">
{{ 'queue.retries-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.retries').hasError('min') &&
!entityForm.get('processingStrategy.retries').hasError('required')">
{{ 'queue.retries-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.failure-percentage</mat-label>
<input type="number" matInput formControlName="failurePercentage" required>
<mat-error *ngIf="entityForm.get('processingStrategy.failurePercentage').hasError('required')">
{{ 'queue.failure-percentage-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.failurePercentage').hasError('min') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('required') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('max')">
{{ 'queue.failure-percentage-min-value' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.failurePercentage').hasError('max') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('required') &&
!entityForm.get('processingStrategy.failurePercentage').hasError('min')">
{{ 'queue.failure-percentage-max-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.pause-between-retries</mat-label>
<input type="number" matInput formControlName="pauseBetweenRetries" required>
<mat-error *ngIf="entityForm.get('processingStrategy.pauseBetweenRetries').hasError('required')">
{{ 'queue.pause-between-retries-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.pauseBetweenRetries').hasError('min') &&
!entityForm.get('processingStrategy.pauseBetweenRetries').hasError('required')">
{{ 'queue.pause-between-retries-min-value' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>queue.max-pause-between-retries</mat-label>
<input type="number" matInput formControlName="maxPauseBetweenRetries" required>
<mat-error *ngIf="entityForm.get('processingStrategy.maxPauseBetweenRetries').hasError('required')">
{{ 'queue.max-pause-between-retries-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('processingStrategy.maxPauseBetweenRetries').hasError('min') &&
!entityForm.get('processingStrategy.maxPauseBetweenRetries').hasError('required')">
{{ 'queue.max-pause-between-retries-min-value' | translate }}
</mat-error>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
</div>
</fieldset>
</form>
</div>

43
ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss

@ -14,46 +14,9 @@
* limitations under the License.
*/
:host ::ng-deep {
.mat-expansion-panel:not([class*='mat-elevation-z']) {
box-shadow: none;
}
.mat-accordion-container {
margin-bottom: 16px;
}
.mat-expansion-panel {
&:hover {
box-shadow: 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
}
&-header {
height: 56px;
border: 1px solid #f2f2f2;
&-title {
align-items: center;
justify-content: space-between;
margin-right: 0;
}
}
&.mat-expanded {
border: none;
box-shadow: 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
.mat-expansion-panel {
&-content {
margin-top: 20px;
}
&-body {
padding-bottom: 10px;
}
}
.queue-form {
.mat-expansion-panel-body {
padding-bottom: 0 !important;
}
}
}

6
ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts

@ -23,8 +23,6 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
import set = Reflect.set;
import { distinctUntilChanged } from 'rxjs/operators';
@Component({
selector: 'tb-queue',
@ -39,7 +37,7 @@ export class QueueComponent extends EntityComponent<QueueInfo> {
processingStrategies: string[] = [];
QueueSubmitStrategyTypes = QueueSubmitStrategyTypes;
hideBatchSize: boolean = false;
hideBatchSize = false;
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
@ -140,7 +138,7 @@ export class QueueComponent extends EntityComponent<QueueInfo> {
}
submitStrategyTypeChanged() {
const form = this.entityForm.get("submitStrategy") as FormGroup;
const form = this.entityForm.get('submitStrategy') as FormGroup;
const type: QueueSubmitStrategyTypes = form.get('type').value;
const batchSizeField = form.get('batchSize');
if (type === QueueSubmitStrategyTypes.BATCH) {

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

@ -16,7 +16,7 @@
import { BaseData, HasId } from '@shared/models/base-data';
import { TenantId } from '@shared/models/id/tenant-id';
import {QueueId} from "@shared/models/id/queue-id";
import {QueueId} from '@shared/models/id/queue-id';
export enum ServiceType {
TB_CORE = 'TB_CORE',
@ -43,9 +43,10 @@ export enum QueueProcessingStrategyTypes {
}
export interface QueueInfo extends BaseData<QueueId> {
name: string;
packProcessingTimeout: number;
partitions: number;
consumerPerPartition: boolean,
consumerPerPartition: boolean;
pollInterval: number;
processingStrategy: {
type: QueueProcessingStrategyTypes,
@ -58,6 +59,6 @@ export interface QueueInfo extends BaseData<QueueId> {
type: QueueSubmitStrategyTypes,
batchSize: number,
};
tenantId: TenantId;
tenantId?: TenantId;
topic: string;
}

4
ui-ngx/src/app/shared/models/tenant.model.ts

@ -18,7 +18,7 @@ import { ContactBased } from '@shared/models/contact-based.model';
import { TenantId } from './id/tenant-id';
import { TenantProfileId } from '@shared/models/id/tenant-profile-id';
import { BaseData } from '@shared/models/base-data';
import {Validators} from "@angular/forms";
import { QueueInfo } from '@shared/models/queue.models';
export enum TenantProfileType {
DEFAULT = 'DEFAULT'
@ -98,7 +98,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan
export interface TenantProfileData {
configuration: TenantProfileConfiguration;
queueConfiguration?: any;
queueConfiguration?: QueueInfo;
}
export interface TenantProfile extends BaseData<TenantProfileId> {

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

@ -2862,7 +2862,10 @@
"max-sms-range": "Maximum number of SMS sent can't be negative",
"max-created-alarms": "Maximum number of alarms created (0 - unlimited)",
"max-created-alarms-required": "Maximum number of alarms created is required.",
"max-created-alarms-range": "Maximum number of alarms created can't be negative"
"max-created-alarms-range": "Maximum number of alarms created can't be negative",
"no-queue": "No Queue configured",
"add-queue": "Add Queue",
"queues-with-count": "Queues ({{count}})"
},
"timeinterval": {
"seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }",

Loading…
Cancel
Save