Browse Source

created tenant profile configuration

pull/3688/head
YevhenBondarenko 6 years ago
committed by Andrew Shvayka
parent
commit
41212e11c0
  1. 2
      application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
  2. 2
      application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java
  3. 2
      application/src/main/java/org/thingsboard/server/service/apiusage/TenantApiUsageState.java
  4. 12
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  5. 2
      application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java
  6. 1
      common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java
  7. 20
      common/data/src/main/java/org/thingsboard/server/common/data/TenantProfileType.java
  8. 45
      common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java
  9. 36
      common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java
  10. 4
      common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java
  11. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java
  12. 3
      dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java
  13. 4
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java
  14. 11
      dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java
  15. 4
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  16. 1
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.ts
  17. 16
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html
  18. 6
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.ts
  19. 15
      ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts
  20. 141
      ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html
  21. 115
      ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts
  22. 27
      ui-ngx/src/app/modules/home/components/profile/tenant/tenant-profile-configuration.component.html
  23. 103
      ui-ngx/src/app/modules/home/components/profile/tenant/tenant-profile-configuration.component.ts
  24. 53
      ui-ngx/src/app/shared/models/tenant.model.ts
  25. 33
      ui-ngx/src/assets/locale/locale.constant-en_US.json

2
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java

@ -5,7 +5,7 @@
* 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
* 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,

2
application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java

@ -5,7 +5,7 @@
* 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
* 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,

2
application/src/main/java/org/thingsboard/server/service/apiusage/TenantApiUsageState.java

@ -20,7 +20,7 @@ import lombok.Setter;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.msg.tools.SchedulerUtils;

12
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -30,7 +30,8 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.CustomerId;
@ -127,6 +128,10 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
public void createDefaultTenantProfiles() throws Exception {
tenantProfileService.findOrCreateDefaultTenantProfile(TenantId.SYS_TENANT_ID);
TenantProfileData tenantProfileData = new TenantProfileData();
DefaultTenantProfileConfiguration configuration = new DefaultTenantProfileConfiguration();
tenantProfileData.setConfiguration(configuration);
TenantProfile isolatedTbCoreProfile = new TenantProfile();
isolatedTbCoreProfile.setDefault(false);
isolatedTbCoreProfile.setName("Isolated TB Core");
@ -134,6 +139,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
isolatedTbCoreProfile.setDescription("Isolated TB Core tenant profile");
isolatedTbCoreProfile.setIsolatedTbCore(true);
isolatedTbCoreProfile.setIsolatedTbRuleEngine(false);
isolatedTbCoreProfile.setProfileData(tenantProfileData);
try {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbCoreProfile);
} catch (DataValidationException e) {
@ -147,6 +153,8 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
isolatedTbRuleEngineProfile.setDescription("Isolated TB Rule Engine tenant profile");
isolatedTbRuleEngineProfile.setIsolatedTbCore(false);
isolatedTbRuleEngineProfile.setIsolatedTbRuleEngine(true);
isolatedTbRuleEngineProfile.setProfileData(tenantProfileData);
try {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbRuleEngineProfile);
} catch (DataValidationException e) {
@ -160,6 +168,8 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
isolatedTbCoreAndTbRuleEngineProfile.setDescription("Isolated TB Core and TB Rule Engine tenant profile");
isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbCore(true);
isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbRuleEngine(true);
isolatedTbCoreAndTbRuleEngineProfile.setProfileData(tenantProfileData);
try {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbCoreAndTbRuleEngineProfile);
} catch (DataValidationException e) {

2
application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java

@ -23,7 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;

1
common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java

@ -21,6 +21,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import java.io.ByteArrayInputStream;
import java.io.IOException;

20
common/data/src/main/java/org/thingsboard/server/common/data/TenantProfileType.java

@ -0,0 +1,20 @@
/**
* Copyright © 2016-2020 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.
*/
package org.thingsboard.server.common.data;
public enum TenantProfileType {
DEFAULT
}

45
common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2020 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.
*/
package org.thingsboard.server.common.data.tenant.profile;
import lombok.Data;
import org.thingsboard.server.common.data.TenantProfileType;
@Data
public class DefaultTenantProfileConfiguration implements TenantProfileConfiguration {
private long maxDevices;
private long maxAssets;
private String transportTenantMsgRateLimit;
private String transportTenantTelemetryMsgRateLimit;
private String transportTenantTelemetryDataPointsRateLimit;
private String transportDeviceMsgRateLimit;
private String transportDeviceTelemetryMsgRateLimit;
private String transportDeviceTelemetryDataPointsRateLimit;
private long maxTransportMessages;
private long maxTransportDataPoints;
private long maxREExecutions;
private long maxJSExecutions;
private long maxDPStorageDays;
private int maxRuleNodeExecutionsPerMessage;
@Override
public TenantProfileType getType() {
return TenantProfileType.DEFAULT;
}
}

36
common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java

@ -0,0 +1,36 @@
/**
* Copyright © 2016-2020 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.
*/
package org.thingsboard.server.common.data.tenant.profile;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.thingsboard.server.common.data.TenantProfileType;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = DefaultTenantProfileConfiguration.class, name = "DEFAULT")})
public interface TenantProfileConfiguration {
@JsonIgnore
TenantProfileType getType();
}

4
common/data/src/main/java/org/thingsboard/server/common/data/TenantProfileData.java → common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
package org.thingsboard.server.common.data.tenant.profile;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
@ -26,6 +26,8 @@ import java.util.Map;
@Data
public class TenantProfileData {
private TenantProfileConfiguration configuration;
@JsonIgnore
private Map<String, Object> properties = new HashMap<>();

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java

@ -18,9 +18,9 @@ package org.thingsboard.server.common.transport.limits;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.common.transport.TransportTenantProfileCache;
import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult;
import org.thingsboard.server.queue.util.TbTransportComponent;

3
dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java

@ -22,14 +22,13 @@ import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.SearchTextEntity;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.dao.util.mapping.JsonBinaryType;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;

4
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java

@ -23,20 +23,18 @@ import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import java.util.Arrays;
import java.util.Collections;

11
dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java

@ -21,13 +21,12 @@ import org.junit.Test;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import java.util.ArrayList;
import java.util.Collections;
@ -188,8 +187,8 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
Assert.assertTrue(pageData.getData().isEmpty());
tenantProfiles.addAll(pageData.getData());
for (int i=0;i<28;i++) {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"+i);
for (int i = 0; i < 28; i++) {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile" + i);
tenantProfiles.add(tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile));
}
@ -224,8 +223,8 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
List<TenantProfile> tenantProfiles = new ArrayList<>();
for (int i=0;i<28;i++) {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"+i);
for (int i = 0; i < 28; i++) {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile" + i);
tenantProfiles.add(tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile));
}

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

@ -113,6 +113,8 @@ import { AlarmScheduleInfoComponent } from './profile/alarm/alarm-schedule-info.
import { AlarmScheduleDialogComponent } from '@home/components/profile/alarm/alarm-schedule-dialog.component';
import { EditAlarmDetailsDialogComponent } from './profile/alarm/edit-alarm-details-dialog.component';
import { AlarmRuleConditionDialogComponent } from '@home/components/profile/alarm/alarm-rule-condition-dialog.component';
import { DefaultTenantProfileConfigurationComponent } from './profile/tenant/default-tenant-profile-configuration.component';
import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-profile-configuration.component';
@NgModule({
declarations:
@ -182,6 +184,8 @@ import { AlarmRuleConditionDialogComponent } from '@home/components/profile/alar
FilterUserInfoDialogComponent,
FilterPredicateValueComponent,
TenantProfileAutocompleteComponent,
DefaultTenantProfileConfigurationComponent,
TenantProfileConfigurationComponent,
TenantProfileDataComponent,
TenantProfileComponent,
TenantProfileDialogComponent,

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

@ -204,7 +204,6 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor,
createTenantProfile($event: Event, profileName: string) {
$event.preventDefault();
const tenantProfile: TenantProfile = {
id: null,
name: profileName
};
this.openTenantProfileDialog(tenantProfile, true);

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

@ -16,9 +16,15 @@
-->
<form [formGroup]="tenantProfileDataFormGroup" style="padding-bottom: 16px;">
<tb-json-object-edit
[required]="required"
label="{{ 'tenant-profile.data' | translate }}"
formControlName="tenantProfileData">
</tb-json-object-edit>
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
<div translate>tenant-profile.profile-configuration</div>
</mat-panel-title>
</mat-expansion-panel-header>
<tb-tenant-profile-configuration
formControlName="configuration"
required>
</tb-tenant-profile-configuration>
</mat-expansion-panel>
</form>

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

@ -62,7 +62,7 @@ export class TenantProfileDataComponent implements ControlValueAccessor, OnInit
ngOnInit() {
this.tenantProfileDataFormGroup = this.fb.group({
tenantProfileData: [null, Validators.required]
configuration: [null, Validators.required]
});
this.tenantProfileDataFormGroup.valueChanges.subscribe(() => {
this.updateModel();
@ -79,13 +79,13 @@ export class TenantProfileDataComponent implements ControlValueAccessor, OnInit
}
writeValue(value: TenantProfileData | null): void {
this.tenantProfileDataFormGroup.get('tenantProfileData').patchValue(value, {emitEvent: false});
this.tenantProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false});
}
private updateModel() {
let tenantProfileData: TenantProfileData = null;
if (this.tenantProfileDataFormGroup.valid) {
tenantProfileData = this.tenantProfileDataFormGroup.getRawValue().tenantProfileData;
tenantProfileData = this.tenantProfileDataFormGroup.getRawValue();
}
this.propagateChange(tenantProfileData);
}

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

@ -18,7 +18,12 @@ import { Component, Inject, Input, Optional } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { TenantProfile } from '@app/shared/models/tenant.model';
import {
createTenantProfileConfiguration,
TenantProfile,
TenantProfileData,
TenantProfileType
} from '@app/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';
@ -56,7 +61,9 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
name: [entity ? entity.name : '', [Validators.required]],
isolatedTbCore: [entity ? entity.isolatedTbCore : false, []],
isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []],
profileData: [entity && !this.isAdd ? entity.profileData : {}, []],
profileData: [entity && !this.isAdd ? entity.profileData : {
configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT)
} as TenantProfileData, []],
description: [entity ? entity.description : '', []],
}
);
@ -66,7 +73,9 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
this.entityForm.patchValue({name: entity.name});
this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore});
this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine});
this.entityForm.patchValue({profileData: entity.profileData});
this.entityForm.patchValue({profileData: !this.isAdd ? entity.profileData: {
configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT)
} as TenantProfileData});
this.entityForm.patchValue({description: entity.description});
}

141
ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html

@ -0,0 +1,141 @@
<!--
Copyright © 2016-2020 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.
-->
<section [formGroup]="defaultTenantProfileConfigurationFormGroup">
<section formGroupName="configuration" fxLayout="column">
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.maximum-devices</mat-label>
<input matInput required min="0" step="1"
formControlName="maxDevices"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxDevices').hasError('required')">
{{ 'tenant-profile.maximum-devices-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxDevices').hasError('min')">
{{ 'tenant-profile.maximum-devices-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.maximum-assets</mat-label>
<input matInput required min="0" step="1"
formControlName="maxAssets"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxAssets').hasError('required')">
{{ 'tenant-profile.maximum-assets-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxAssets').hasError('min')">
{{ 'tenant-profile.maximum-assets-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.max-transport-messages</mat-label>
<input matInput required min="0" step="1"
formControlName="maxTransportMessages"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxTransportMessages').hasError('required')">
{{ 'tenant-profile.max-transport-messages-range' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxTransportMessages').hasError('min')">
{{ 'tenant-profile.max-transport-messages-required' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.max-transport-data-points</mat-label>
<input matInput required min="0" step="1"
formControlName="maxTransportDataPoints"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxTransportDataPoints').hasError('required')">
{{ 'tenant-profile.max-transport-data-points-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxTransportDataPoints').hasError('min')">
{{ 'tenant-profile.max-transport-data-points-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.max-r-e-executions</mat-label>
<input matInput required min="0" step="1"
formControlName="maxREExecutions"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxREExecutions').hasError('required')">
{{ 'tenant-profile.max-r-e-executions-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxREExecutions').hasError('min')">
{{ 'tenant-profile.max-r-e-executions-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.max-j-s-executions</mat-label>
<input matInput required min="0" step="1"
formControlName="maxJSExecutions"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxJSExecutions').hasError('required')">
{{ 'tenant-profile.max-j-s-executions-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxJSExecutions').hasError('min')">
{{ 'tenant-profile.max-j-s-executions-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.max-d-p-storage-days</mat-label>
<input matInput required min="0" step="1"
formControlName="maxDPStorageDays"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxDPStorageDays').hasError('required')">
{{ 'tenant-profile.max-d-p-storage-days-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxDPStorageDays').hasError('min')">
{{ 'tenant-profile.max-d-p-storage-days-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.max-rule-node-executions-per-message</mat-label>
<input matInput required min="0" step="1"
formControlName="maxRuleNodeExecutionsPerMessage"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxRuleNodeExecutionsPerMessage').hasError('required')">
{{ 'tenant-profile.max-rule-node-executions-per-message-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('configuration.maxRuleNodeExecutionsPerMessage').hasError('min')">
{{ 'tenant-profile.max-rule-node-executions-per-message-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.transport-tenant-msg-rate-limit</mat-label>
<input matInput formControlName="transportTenantMsgRateLimit">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.transport-tenant-telemetry-msg-rate-limit</mat-label>
<input matInput formControlName="transportTenantTelemetryMsgRateLimit">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.transport-tenant-telemetry-data-points-rate-limit</mat-label>
<input matInput formControlName="transportTenantTelemetryDataPointsRateLimit">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.transport-device-msg-rate-limit</mat-label>
<input matInput formControlName="transportDeviceMsgRateLimit">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.transport-device-telemetry-msg-rate-limit</mat-label>
<input matInput formControlName="transportDeviceTelemetryMsgRateLimit">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.transport-device-telemetry-data-points-rate-limit</mat-label>
<input matInput formControlName="transportDeviceTelemetryDataPointsRateLimit">
</mat-form-field>
</section>
</section>

115
ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts

@ -0,0 +1,115 @@
///
/// Copyright © 2016-2020 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 { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DefaultTenantProfileConfiguration,
TenantProfileConfiguration,
TenantProfileType
} from '@shared/models/tenant.model';
import { isDefinedAndNotNull } from '@core/utils';
@Component({
selector: 'tb-default-tenant-profile-configuration',
templateUrl: './default-tenant-profile-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DefaultTenantProfileConfigurationComponent),
multi: true
}]
})
export class DefaultTenantProfileConfigurationComponent implements ControlValueAccessor, OnInit {
defaultTenantProfileConfigurationFormGroup: FormGroup;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@Input()
disabled: boolean;
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.defaultTenantProfileConfigurationFormGroup = this.fb.group({
configuration: this.fb.group({
maxDevices: [null, [Validators.required, Validators.min(0)]],
maxAssets: [null, [Validators.required, Validators.min(0)]],
transportTenantMsgRateLimit: [null, []],
transportTenantTelemetryMsgRateLimit: [null, []],
transportTenantTelemetryDataPointsRateLimit: [null, []],
transportDeviceMsgRateLimit: [null, []],
transportDeviceTelemetryMsgRateLimit: [null, []],
transportDeviceTelemetryDataPointsRateLimit: [null, []],
maxTransportMessages: [null, [Validators.required, Validators.min(0)]],
maxTransportDataPoints: [null, [Validators.required, Validators.min(0)]],
maxREExecutions: [null, [Validators.required, Validators.min(0)]],
maxJSExecutions: [null, [Validators.required, Validators.min(0)]],
maxDPStorageDays: [null, [Validators.required, Validators.min(0)]],
maxRuleNodeExecutionsPerMessage: [null, [Validators.required, Validators.min(0)]]
})
});
this.defaultTenantProfileConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.defaultTenantProfileConfigurationFormGroup.disable({emitEvent: false});
} else {
this.defaultTenantProfileConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: DefaultTenantProfileConfiguration | null): void {
if (isDefinedAndNotNull(value)) {
this.defaultTenantProfileConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
}
}
private updateModel() {
let configuration: TenantProfileConfiguration = null;
if (this.defaultTenantProfileConfigurationFormGroup.valid) {
configuration = this.defaultTenantProfileConfigurationFormGroup.getRawValue().configuration;
configuration.type = TenantProfileType.DEFAULT;
}
this.propagateChange(configuration);
}
}

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

@ -0,0 +1,27 @@
<!--
Copyright © 2016-2020 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 [formGroup]="tenantProfileConfigurationFormGroup">
<div [ngSwitch]="type">
<ng-template [ngSwitchCase]="tenantProfileType.DEFAULT">
<tb-default-tenant-profile-configuration
[required]="required"
formControlName="configuration">
</tb-default-tenant-profile-configuration>
</ng-template>
</div>
</div>

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

@ -0,0 +1,103 @@
///
/// Copyright © 2016-2020 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 { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { deepClone } from '@core/utils';
import { TenantProfileConfiguration, TenantProfileType } from '@shared/models/tenant.model';
@Component({
selector: 'tb-tenant-profile-configuration',
templateUrl: './tenant-profile-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TenantProfileConfigurationComponent),
multi: true
}]
})
export class TenantProfileConfigurationComponent implements ControlValueAccessor, OnInit {
tenantProfileType = TenantProfileType;
tenantProfileConfigurationFormGroup: FormGroup;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@Input()
disabled: boolean;
type: TenantProfileType;
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.tenantProfileConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.tenantProfileConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.tenantProfileConfigurationFormGroup.disable({emitEvent: false});
} else {
this.tenantProfileConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: TenantProfileConfiguration | null): void {
this.type = value?.type;
const configuration = deepClone(value);
if (configuration) {
delete configuration.type;
}
this.tenantProfileConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
}
private updateModel() {
let configuration: TenantProfileConfiguration = null;
if (this.tenantProfileConfigurationFormGroup.valid) {
configuration = this.tenantProfileConfigurationFormGroup.getRawValue().configuration;
configuration.type = this.type;
}
this.propagateChange(configuration);
}
}

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

@ -19,8 +19,59 @@ import { TenantId } from './id/tenant-id';
import { TenantProfileId } from '@shared/models/id/tenant-profile-id';
import { BaseData } from '@shared/models/base-data';
export enum TenantProfileType {
DEFAULT = 'DEFAULT'
}
export interface DefaultTenantProfileConfiguration {
maxDevices: number;
maxAssets: number;
transportTenantMsgRateLimit?: string;
transportTenantTelemetryMsgRateLimit?: string;
transportTenantTelemetryDataPointsRateLimit?: string;
transportDeviceMsgRateLimit?: string;
transportDeviceTelemetryMsgRateLimit?: string;
transportDeviceTelemetryDataPointsRateLimit?: string;
maxTransportMessages: number;
maxTransportDataPoints: number;
maxREExecutions: number;
maxJSExecutions: number;
maxDPStorageDays: number;
maxRuleNodeExecutionsPerMessage: number;
}
export type TenantProfileConfigurations = DefaultTenantProfileConfiguration;
export interface TenantProfileConfiguration extends TenantProfileConfigurations {
type: TenantProfileType;
}
export function createTenantProfileConfiguration(type: TenantProfileType): TenantProfileConfiguration {
let configuration: TenantProfileConfiguration = null;
if (type) {
switch (type) {
case TenantProfileType.DEFAULT:
const defaultConfiguration: DefaultTenantProfileConfiguration = {
maxDevices: 0,
maxAssets: 0,
maxTransportMessages: 0,
maxTransportDataPoints: 0,
maxREExecutions: 0,
maxJSExecutions: 0,
maxDPStorageDays: 0,
maxRuleNodeExecutionsPerMessage: 0
};
configuration = {...defaultConfiguration, type: TenantProfileType.DEFAULT};
break;
}
}
return configuration;
}
export interface TenantProfileData {
[key: string]: string;
configuration: TenantProfileConfiguration;
}
export interface TenantProfile extends BaseData<TenantProfileId> {

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

@ -1923,6 +1923,7 @@
"name": "Name",
"name-required": "Name is required.",
"data": "Profile data",
"profile-configuration": "Profile configuration",
"description": "Description",
"default": "Default",
"delete-tenant-profile-title": "Are you sure you want to delete the tenant profile '{{tenantProfileName}}'?",
@ -1932,7 +1933,37 @@
"set-default-tenant-profile-title": "Are you sure you want to make the tenant profile '{{tenantProfileName}}' default?",
"set-default-tenant-profile-text": "After the confirmation the tenant profile will be marked as default and will be used for new tenants with no profile specified.",
"no-tenant-profiles-found": "No tenant profiles found.",
"create-new-tenant-profile": "Create a new one!"
"create-new-tenant-profile": "Create a new one!",
"maximum-devices": "Maximum number of devices (0 - unlimited)",
"maximum-devices-required": "Maximum number of devices is required.",
"maximum-devices-range": "Minimum number of devices can't be negative",
"maximum-assets": "Maximum number of assets (0 - unlimited)",
"maximum-assets-required": "Maximum number of assets is required.",
"maximum-assets-range": "Maximum number of assets can't be negative",
"transport-tenant-msg-rate-limit": "Transport tenant messages rate limit.",
"transport-tenant-telemetry-msg-rate-limit": "Transport tenant telemetry messages rate limit.",
"transport-tenant-telemetry-data-points-rate-limit": "Transport tenant telemetry data points rate limit.",
"transport-device-msg-rate-limit": "Transport device messages rate limit.",
"transport-device-telemetry-msg-rate-limit": "Transport device telemetry messages rate limit.",
"transport-device-telemetry-data-points-rate-limit": "Transport device telemetry data points rate limit.",
"max-transport-messages": "Maximum number of transport messages (0 - unlimited)",
"max-transport-messages-required": "Maximum number of transport messages is required.",
"max-transport-messages-range": "Maximum number of transport messages can't be negative",
"max-transport-data-points": "Maximum number of transport data points (0 - unlimited)",
"max-transport-data-points-required": "Maximum number of transport data points is required.",
"max-transport-data-points-range": "Minimum number of transport data points can't be negative",
"max-r-e-executions": "Maximum number of Rule Engine executions (0 - unlimited)",
"max-r-e-executions-required": "Maximum number of Rule Engine executions is required.",
"max-r-e-executions-range": "Minimum number of Rule Engine executions can't be negative",
"max-j-s-executions": "Maximum number of JavaScript executions (0 - unlimited)",
"max-j-s-executions-required": "Maximum number of JavaScript executions is required.",
"max-j-s-executions-range": "Minimum number of JavaScript executions can't be negative",
"max-d-p-storage-days": "Maximum number of data points storage days (0 - unlimited)",
"max-d-p-storage-days-required": "Maximum number of data points storage days is required.",
"max-d-p-storage-days-range": "Minimum number of data points storage days can't be negative",
"max-rule-node-executions-per-message": "Maximum number of rule node executions per message (0 - unlimited)",
"max-rule-node-executions-per-message-required": "Maximum number of rule node executions per message is required.",
"max-rule-node-executions-per-message-range": "Minimum number of rule node executions per message can't be negative"
},
"timeinterval": {
"seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }",

Loading…
Cancel
Save