Browse Source

Merge branch 'master' of github.com:thingsboard/thingsboard

pull/3791/head
Andrii Shvaika 6 years ago
parent
commit
4e8b0aa674
  1. 2
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  2. 2
      application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
  3. 2
      application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java
  4. 6
      application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java
  5. 4
      application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/sms/aws/AwsSmsSender.java
  7. 2
      application/src/main/java/org/thingsboard/server/service/sms/twilio/TwilioSmsSender.java
  8. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sms/config/AwsSnsSmsProviderConfiguration.java
  9. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sms/config/SmsProviderConfiguration.java
  10. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sms/config/SmsProviderType.java
  11. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sms/config/TestSmsRequest.java
  12. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sms/config/TwilioSmsProviderConfiguration.java
  13. 11
      rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
  14. 2
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/SmsService.java
  15. 2
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/sms/SmsSenderFactory.java
  16. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNodeConfiguration.java
  17. 1
      ui-ngx/src/app/core/services/menu.models.ts
  18. 13
      ui-ngx/src/app/core/services/menu.service.ts
  19. 44
      ui-ngx/src/app/core/services/utils.service.ts
  20. 9
      ui-ngx/src/app/core/utils.ts
  21. 2
      ui-ngx/src/app/modules/home/components/widget/action/custom-action.models.ts
  22. 2
      ui-ngx/src/app/modules/home/menu/menu-link.component.html
  23. 41
      ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts
  24. 18
      ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.html
  25. 20
      ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.scss
  26. 41
      ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts
  27. 38
      ui-ngx/src/app/modules/home/pages/api-usage/api-usage.module.ts
  28. 4355
      ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw
  29. 2
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.html
  30. 31
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.ts
  31. 3
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard.module.ts
  32. 2
      ui-ngx/src/app/modules/home/pages/dashboard/states/state-controller.component.ts
  33. 2
      ui-ngx/src/app/modules/home/pages/home-pages.module.ts
  34. 2
      ui-ngx/src/app/shared/models/constants.ts
  35. 3
      ui-ngx/src/app/shared/models/rule-node.models.ts
  36. 3
      ui-ngx/src/assets/locale/locale.constant-en_US.json

2
application/src/main/java/org/thingsboard/server/controller/AdminController.java

@ -26,7 +26,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.SmsService; import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.rule.engine.api.sms.config.TestSmsRequest; import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;

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

@ -166,7 +166,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
long newValue = tenantState.add(recordKey, kvProto.getValue()); long newValue = tenantState.add(recordKey, kvProto.getValue());
updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue))); updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue)));
long newHourlyValue = tenantState.addToHourly(recordKey, kvProto.getValue()); long newHourlyValue = tenantState.addToHourly(recordKey, kvProto.getValue());
updatedEntries.add(new BasicTsKvEntry(hourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue))); updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue)));
apiFeatures.add(recordKey.getApiFeature()); apiFeatures.add(recordKey.getApiFeature());
} }
result = tenantState.checkStateUpdatedDueToThreshold(apiFeatures); result = tenantState.checkStateUpdatedDueToThreshold(apiFeatures);

2
application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java

@ -112,7 +112,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
public ProvisionResponse provisionDevice(ProvisionRequest provisionRequest) { public ProvisionResponse provisionDevice(ProvisionRequest provisionRequest) {
String provisionRequestKey = provisionRequest.getCredentials().getProvisionDeviceKey(); String provisionRequestKey = provisionRequest.getCredentials().getProvisionDeviceKey();
String provisionRequestSecret = provisionRequest.getCredentials().getProvisionDeviceSecret(); String provisionRequestSecret = provisionRequest.getCredentials().getProvisionDeviceSecret();
if (provisionRequest.getDeviceName() != null) { if (!StringUtils.isEmpty(provisionRequest.getDeviceName())) {
provisionRequest.setDeviceName(provisionRequest.getDeviceName().trim()); provisionRequest.setDeviceName(provisionRequest.getDeviceName().trim());
if (StringUtils.isEmpty(provisionRequest.getDeviceName())) { if (StringUtils.isEmpty(provisionRequest.getDeviceName())) {
log.warn("Provision request contains empty device name!"); log.warn("Provision request contains empty device name!");

6
application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java

@ -18,9 +18,9 @@ package org.thingsboard.server.service.sms;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.sms.SmsSender; import org.thingsboard.rule.engine.api.sms.SmsSender;
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
import org.thingsboard.rule.engine.api.sms.config.AwsSnsSmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.AwsSnsSmsProviderConfiguration;
import org.thingsboard.rule.engine.api.sms.config.SmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
import org.thingsboard.rule.engine.api.sms.config.TwilioSmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.TwilioSmsProviderConfiguration;
import org.thingsboard.server.service.sms.aws.AwsSmsSender; import org.thingsboard.server.service.sms.aws.AwsSmsSender;
import org.thingsboard.server.service.sms.twilio.TwilioSmsSender; import org.thingsboard.server.service.sms.twilio.TwilioSmsSender;

4
application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java

@ -22,8 +22,8 @@ import org.springframework.stereotype.Service;
import org.thingsboard.rule.engine.api.SmsService; import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.rule.engine.api.sms.SmsSender; import org.thingsboard.rule.engine.api.sms.SmsSender;
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
import org.thingsboard.rule.engine.api.sms.config.SmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
import org.thingsboard.rule.engine.api.sms.config.TestSmsRequest; import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;

2
application/src/main/java/org/thingsboard/server/service/sms/aws/AwsSmsSender.java

@ -23,7 +23,7 @@ import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.PublishRequest; import com.amazonaws.services.sns.model.PublishRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.thingsboard.rule.engine.api.sms.config.AwsSnsSmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.AwsSnsSmsProviderConfiguration;
import org.thingsboard.rule.engine.api.sms.exception.SmsException; import org.thingsboard.rule.engine.api.sms.exception.SmsException;
import org.thingsboard.rule.engine.api.sms.exception.SmsSendException; import org.thingsboard.rule.engine.api.sms.exception.SmsSendException;
import org.thingsboard.server.service.sms.AbstractSmsSender; import org.thingsboard.server.service.sms.AbstractSmsSender;

2
application/src/main/java/org/thingsboard/server/service/sms/twilio/TwilioSmsSender.java

@ -19,7 +19,7 @@ import com.twilio.http.TwilioRestClient;
import com.twilio.rest.api.v2010.account.Message; import com.twilio.rest.api.v2010.account.Message;
import com.twilio.type.PhoneNumber; import com.twilio.type.PhoneNumber;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.thingsboard.rule.engine.api.sms.config.TwilioSmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.TwilioSmsProviderConfiguration;
import org.thingsboard.rule.engine.api.sms.exception.SmsException; import org.thingsboard.rule.engine.api.sms.exception.SmsException;
import org.thingsboard.rule.engine.api.sms.exception.SmsSendException; import org.thingsboard.rule.engine.api.sms.exception.SmsSendException;
import org.thingsboard.server.service.sms.AbstractSmsSender; import org.thingsboard.server.service.sms.AbstractSmsSender;

2
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/sms/config/AwsSnsSmsProviderConfiguration.java → common/data/src/main/java/org/thingsboard/server/common/data/sms/config/AwsSnsSmsProviderConfiguration.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.api.sms.config; package org.thingsboard.server.common.data.sms.config;
import lombok.Data; import lombok.Data;

2
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/sms/config/SmsProviderConfiguration.java → common/data/src/main/java/org/thingsboard/server/common/data/sms/config/SmsProviderConfiguration.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.api.sms.config; package org.thingsboard.server.common.data.sms.config;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

2
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/sms/config/SmsProviderType.java → common/data/src/main/java/org/thingsboard/server/common/data/sms/config/SmsProviderType.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.api.sms.config; package org.thingsboard.server.common.data.sms.config;
public enum SmsProviderType { public enum SmsProviderType {
AWS_SNS, AWS_SNS,

2
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/sms/config/TestSmsRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sms/config/TestSmsRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.api.sms.config; package org.thingsboard.server.common.data.sms.config;
import lombok.Data; import lombok.Data;

2
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/sms/config/TwilioSmsProviderConfiguration.java → common/data/src/main/java/org/thingsboard/server/common/data/sms/config/TwilioSmsProviderConfiguration.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.api.sms.config; package org.thingsboard.server.common.data.sms.config;
import lombok.Data; import lombok.Data;

11
rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java

@ -109,6 +109,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundle;
@ -218,7 +219,11 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
} }
public void sendTestMail(AdminSettings adminSettings) { public void sendTestMail(AdminSettings adminSettings) {
restTemplate.postForEntity(baseURL + "/api/admin/settings/testMail", adminSettings, AdminSettings.class); restTemplate.postForLocation(baseURL + "/api/admin/settings/testMail", adminSettings);
}
public void sendTestSms(TestSmsRequest testSmsRequest) {
restTemplate.postForLocation(baseURL + "/api/admin/settings/testSms", testSmsRequest);
} }
public Optional<SecuritySettings> getSecuritySettings() { public Optional<SecuritySettings> getSecuritySettings() {
@ -1714,6 +1719,10 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
return restTemplate.postForEntity(baseURL + "/api/oauth2/config", oauth2Params, OAuth2ClientsParams.class).getBody(); return restTemplate.postForEntity(baseURL + "/api/oauth2/config", oauth2Params, OAuth2ClientsParams.class).getBody();
} }
public String getLoginProcessingUrl() {
return restTemplate.getForEntity(baseURL + "/api/oauth2/loginProcessingUrl", String.class).getBody();
}
public void handleOneWayDeviceRPCRequest(DeviceId deviceId, JsonNode requestBody) { public void handleOneWayDeviceRPCRequest(DeviceId deviceId, JsonNode requestBody) {
restTemplate.postForLocation(baseURL + "/api/plugins/rpc/oneway/{deviceId}", requestBody, deviceId.getId()); restTemplate.postForLocation(baseURL + "/api/plugins/rpc/oneway/{deviceId}", requestBody, deviceId.getId());
} }

2
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/SmsService.java

@ -15,7 +15,7 @@
*/ */
package org.thingsboard.rule.engine.api; package org.thingsboard.rule.engine.api;
import org.thingsboard.rule.engine.api.sms.config.TestSmsRequest; import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;

2
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/sms/SmsSenderFactory.java

@ -15,7 +15,7 @@
*/ */
package org.thingsboard.rule.engine.api.sms; package org.thingsboard.rule.engine.api.sms;
import org.thingsboard.rule.engine.api.sms.config.SmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
public interface SmsSenderFactory { public interface SmsSenderFactory {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNodeConfiguration.java

@ -17,7 +17,7 @@ package org.thingsboard.rule.engine.sms;
import lombok.Data; import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.api.sms.config.SmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
@Data @Data
public class TbSendSmsNodeConfiguration implements NodeConfiguration { public class TbSendSmsNodeConfiguration implements NodeConfiguration {

1
ui-ngx/src/app/core/services/menu.models.ts

@ -23,6 +23,7 @@ export interface MenuSection extends HasUUID{
type: MenuSectionType; type: MenuSectionType;
path: string; path: string;
icon: string; icon: string;
notExact?: boolean;
isMdiIcon?: boolean; isMdiIcon?: boolean;
height?: string; height?: string;
pages?: Array<MenuSection>; pages?: Array<MenuSection>;

13
ui-ngx/src/app/core/services/menu.service.ts

@ -288,6 +288,14 @@ export class MenuService {
type: 'link', type: 'link',
path: '/auditLogs', path: '/auditLogs',
icon: 'track_changes' icon: 'track_changes'
},
{
id: guid(),
name: 'api-usage.api-usage',
type: 'link',
path: '/usage',
icon: 'insert_chart',
notExact: true
} }
); );
return sections; return sections;
@ -374,6 +382,11 @@ export class MenuService {
name: 'audit-log.audit-logs', name: 'audit-log.audit-logs',
icon: 'track_changes', icon: 'track_changes',
path: '/auditLogs' path: '/auditLogs'
},
{
name: 'api-usage.api-usage',
icon: 'insert_chart',
path: '/usage'
} }
] ]
} }

44
ui-ngx/src/app/core/services/utils.service.ts

@ -21,17 +21,18 @@ import { Inject, Injectable, NgZone } from '@angular/core';
import { WINDOW } from '@core/services/window.service'; import { WINDOW } from '@core/services/window.service';
import { ExceptionData } from '@app/shared/models/error.models'; import { ExceptionData } from '@app/shared/models/error.models';
import { import {
baseUrl,
createLabelFromDatasource, createLabelFromDatasource,
deepClone, deepClone,
deleteNullProperties, deleteNullProperties,
guid, guid,
isDefined, isDefined,
isDefinedAndNotNull, isDefinedAndNotNull, isString,
isUndefined isUndefined
} from '@core/utils'; } from '@core/utils';
import { WindowMessage } from '@shared/models/window-message.model'; import { WindowMessage } from '@shared/models/window-message.model';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { customTranslationsPrefix } from '@app/shared/models/constants'; import { customTranslationsPrefix, i18nPrefix } from '@app/shared/models/constants';
import { DataKey, Datasource, DatasourceType, KeyInfo } from '@shared/models/widget.models'; import { DataKey, Datasource, DatasourceType, KeyInfo } from '@shared/models/widget.models';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
import { DataKeyType } from '@app/shared/models/telemetry/telemetry.models'; import { DataKeyType } from '@app/shared/models/telemetry/telemetry.models';
@ -42,6 +43,8 @@ import jsonSchemaDefaults from 'json-schema-defaults';
import materialIconsCodepoints from '!raw-loader!material-design-icons/iconfont/codepoints'; import materialIconsCodepoints from '!raw-loader!material-design-icons/iconfont/codepoints';
import { Observable, of, ReplaySubject } from 'rxjs'; import { Observable, of, ReplaySubject } from 'rxjs';
const i18nRegExp = new RegExp(`{${i18nPrefix}:[^{}]+}`, 'g');
const predefinedFunctions: { [func: string]: string } = { const predefinedFunctions: { [func: string]: string } = {
Sin: 'return Math.round(1000*Math.sin(time/5000));', Sin: 'return Math.round(1000*Math.sin(time/5000));',
Cos: 'return Math.round(1000*Math.cos(time/5000));', Cos: 'return Math.round(1000*Math.cos(time/5000));',
@ -107,8 +110,8 @@ export class UtilsService {
materialIcons: Array<string> = []; materialIcons: Array<string> = [];
constructor(@Inject(WINDOW) private window: Window, constructor(@Inject(WINDOW) private window: Window,
private zone: NgZone, private zone: NgZone,
private translate: TranslateService) { private translate: TranslateService) {
let frame: Element = null; let frame: Element = null;
try { try {
frame = window.frameElement; frame = window.frameElement;
@ -221,8 +224,31 @@ export class UtilsService {
} }
public customTranslation(translationValue: string, defaultValue: string): string { public customTranslation(translationValue: string, defaultValue: string): string {
if (translationValue && isString(translationValue)) {
if (translationValue.includes(`{${i18nPrefix}`)) {
const matches = translationValue.match(i18nRegExp);
let result = translationValue;
for (const match of matches) {
const translationId = match.substring(6, match.length - 1);
result = result.replace(match, this.doTranslate(translationId, match));
}
return result;
} else {
return this.doTranslate(translationValue, defaultValue, customTranslationsPrefix);
}
} else {
return translationValue;
}
}
private doTranslate(translationValue: string, defaultValue: string, prefix?: string): string {
let result: string; let result: string;
const translationId = customTranslationsPrefix + translationValue; let translationId;
if (prefix) {
translationId = prefix + translationValue;
} else {
translationId = translationValue;
}
const translation = this.translate.instant(translationId); const translation = this.translate.instant(translationId);
if (translation !== translationId) { if (translation !== translationId) {
result = translation + ''; result = translation + '';
@ -384,7 +410,7 @@ export class UtilsService {
} }
public updateQueryParam(name: string, value: string | null) { public updateQueryParam(name: string, value: string | null) {
const baseUrl = [this.window.location.protocol, '//', this.window.location.host, this.window.location.pathname].join(''); const baseUrlPart = [baseUrl(), this.window.location.pathname].join('');
const urlQueryString = this.window.location.search; const urlQueryString = this.window.location.search;
let newParam = ''; let newParam = '';
let params = ''; let params = '';
@ -404,7 +430,11 @@ export class UtilsService {
} else if (newParam) { } else if (newParam) {
params = '?' + newParam; params = '?' + newParam;
} }
this.window.history.replaceState({}, '', baseUrl + params); this.window.history.replaceState({}, '', baseUrlPart + params);
}
public baseUrl(): string {
return baseUrl();
} }
public deepClone<T>(target: T, ignoreFields?: string[]): T { public deepClone<T>(target: T, ignoreFields?: string[]): T {

9
ui-ngx/src/app/core/utils.ts

@ -385,6 +385,15 @@ export function padValue(val: any, dec: number): string {
return strVal; return strVal;
} }
export function baseUrl(): string {
let url = window.location.protocol + '//' + window.location.hostname;
const port = window.location.port;
if (port && port.length > 0 && port !== '80' && port !== '443') {
url += ':' + port;
}
return url;
}
export function sortObjectKeys<T>(obj: T): T { export function sortObjectKeys<T>(obj: T): T {
return Object.keys(obj).sort().reduce((acc, key) => { return Object.keys(obj).sort().reduce((acc, key) => {
acc[key] = obj[key]; acc[key] = obj[key];

2
ui-ngx/src/app/modules/home/components/widget/action/custom-action.models.ts

@ -71,7 +71,7 @@ const customPrettyActionCompletions: TbEditorCompletions = {
} }
}, },
...customActionCompletions ...customActionCompletions
} };
export const CustomActionEditorCompleter = new TbEditorCompleter(customActionCompletions); export const CustomActionEditorCompleter = new TbEditorCompleter(customActionCompletions);
export const CustomPrettyActionEditorCompleter = new TbEditorCompleter(customPrettyActionCompletions); export const CustomPrettyActionEditorCompleter = new TbEditorCompleter(customPrettyActionCompletions);

2
ui-ngx/src/app/modules/home/menu/menu-link.component.html

@ -15,7 +15,7 @@
limitations under the License. limitations under the License.
--> -->
<a mat-button routerLinkActive="tb-active" [routerLinkActiveOptions]="{exact: true}" routerLink="{{section.path}}"> <a mat-button routerLinkActive="tb-active" [routerLinkActiveOptions]="{exact: !section.notExact}" routerLink="{{section.path}}">
<mat-icon *ngIf="!section.isMdiIcon && section.icon != null" class="material-icons">{{section.icon}}</mat-icon> <mat-icon *ngIf="!section.isMdiIcon && section.icon != null" class="material-icons">{{section.icon}}</mat-icon>
<mat-icon *ngIf="section.isMdiIcon && section.icon != null" [svgIcon]="section.icon"></mat-icon> <mat-icon *ngIf="section.isMdiIcon && section.icon != null" [svgIcon]="section.icon"></mat-icon>
<span>{{section.name | translate}}</span> <span>{{section.name | translate}}</span>

41
ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts

@ -0,0 +1,41 @@
///
/// 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 { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { Authority } from '@shared/models/authority.enum';
import { ApiUsageComponent } from '@home/pages/api-usage/api-usage.component';
const routes: Routes = [
{
path: 'usage',
component: ApiUsageComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'api-usage.api-usage',
breadcrumb: {
label: 'api-usage.api-usage',
icon: 'insert_chart'
}
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ApiUsageRoutingModule { }

18
ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.html

@ -0,0 +1,18 @@
<!--
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.
-->
<tb-dashboard-page [embedded]="true" [dashboard]="apiUsageDashboard"></tb-dashboard-page>

20
ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.scss

@ -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.
*/
:host {
width: 100%;
height: 100%;
}

41
ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts

@ -0,0 +1,41 @@
///
/// 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, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { PageComponent } from '@shared/components/page.component';
import apiUsageDashboardJson from '!raw-loader!./api_usage_json.raw';
import { Dashboard } from '@shared/models/dashboard.models';
@Component({
selector: 'tb-api-usage',
templateUrl: './api-usage.component.html',
styleUrls: ['./api-usage.component.scss']
})
export class ApiUsageComponent extends PageComponent implements OnInit {
apiUsageDashboard: Dashboard;
constructor(protected store: Store<AppState>) {
super(store);
}
ngOnInit() {
this.apiUsageDashboard = JSON.parse(apiUsageDashboardJson);
}
}

38
ui-ngx/src/app/modules/home/pages/api-usage/api-usage.module.ts

@ -0,0 +1,38 @@
///
/// 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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@app/shared/shared.module';
import { HomeComponentsModule } from '@modules/home/components/home-components.module';
import { ApiUsageComponent } from '@home/pages/api-usage/api-usage.component';
import { DashboardModule } from '@home/pages/dashboard/dashboard.module';
import { ApiUsageRoutingModule } from '@home/pages/api-usage/api-usage-routing.module';
@NgModule({
declarations:
[
ApiUsageComponent
],
imports: [
CommonModule,
SharedModule,
HomeComponentsModule,
DashboardModule,
ApiUsageRoutingModule
]
})
export class ApiUsageModule { }

4355
ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw

File diff suppressed because one or more lines are too long

2
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.html

@ -196,7 +196,7 @@
matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon>done</mat-icon> <mat-icon>done</mat-icon>
</button> </button>
<button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen" <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen && !embedded"
mat-fab color="accent" class="tb-btn-footer" mat-fab color="accent" class="tb-btn-footer"
[ngClass]="{'tb-hide': isAddingWidget || (isLoading$ | async)}" [ngClass]="{'tb-hide': isAddingWidget || (isLoading$ | async)}"
[disabled]="isLoading$ | async" [disabled]="isLoading$ | async"

31
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.ts

@ -14,7 +14,17 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { ChangeDetectorRef, Component, Inject, NgZone, OnDestroy, ViewChild, ViewEncapsulation } from '@angular/core'; import {
ChangeDetectorRef,
Component,
Inject,
Input,
NgZone,
OnDestroy,
OnInit,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { PageComponent } from '@shared/components/page.component'; import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
@ -98,12 +108,16 @@ import { Filters } from '@shared/models/query/query.models';
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
// changeDetection: ChangeDetectionStrategy.OnPush // changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class DashboardPageComponent extends PageComponent implements IDashboardController, OnDestroy { export class DashboardPageComponent extends PageComponent implements IDashboardController, OnInit, OnDestroy {
authState: AuthState = getCurrentAuthState(this.store); authState: AuthState = getCurrentAuthState(this.store);
authUser: AuthUser = this.authState.authUser; authUser: AuthUser = this.authState.authUser;
@Input()
embedded = false;
@Input()
dashboard: Dashboard; dashboard: Dashboard;
dashboardConfiguration: DashboardConfiguration; dashboardConfiguration: DashboardConfiguration;
@ -239,19 +253,26 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
private cd: ChangeDetectorRef) { private cd: ChangeDetectorRef) {
super(store); super(store);
}
ngOnInit() {
this.rxSubscriptions.push(this.route.data.subscribe( this.rxSubscriptions.push(this.route.data.subscribe(
(data) => { (data) => {
if (this.embedded) {
data.dashboard = this.dashboard;
data.widgetEditMode = false;
data.singlePageMode = false;
}
this.init(data); this.init(data);
this.runChangeDetection(); this.runChangeDetection();
} }
)); ));
this.rxSubscriptions.push(this.breakpointObserver this.rxSubscriptions.push(this.breakpointObserver
.observe(MediaBreakpoints['gt-sm']) .observe(MediaBreakpoints['gt-sm'])
.subscribe((state: BreakpointState) => { .subscribe((state: BreakpointState) => {
this.isMobile = !state.matches; this.isMobile = !state.matches;
} }
)); ));
} }
private init(data: any) { private init(data: any) {

3
ui-ngx/src/app/modules/home/pages/dashboard/dashboard.module.ts

@ -53,6 +53,9 @@ import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.c
ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogComponent,
DashboardStateDialogComponent DashboardStateDialogComponent
], ],
exports: [
DashboardPageComponent
],
imports: [ imports: [
CommonModule, CommonModule,
SharedModule, SharedModule,

2
ui-ngx/src/app/modules/home/pages/dashboard/states/state-controller.component.ts

@ -98,7 +98,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon
ngOnInit(): void { ngOnInit(): void {
this.rxSubscriptions.push(this.route.queryParamMap.subscribe((paramMap) => { this.rxSubscriptions.push(this.route.queryParamMap.subscribe((paramMap) => {
const dashboardId = this.route.snapshot.params.dashboardId; const dashboardId = this.route.snapshot.params.dashboardId || '';
if (this.dashboardId === dashboardId) { if (this.dashboardId === dashboardId) {
const newState = this.decodeStateParam(paramMap.get('state')); const newState = this.decodeStateParam(paramMap.get('state'));
if (this.currentState !== newState) { if (this.currentState !== newState) {

2
ui-ngx/src/app/modules/home/pages/home-pages.module.ts

@ -33,6 +33,7 @@ import { TenantProfileModule } from './tenant-profile/tenant-profile.module';
import { MODULES_MAP } from '@shared/public-api'; import { MODULES_MAP } from '@shared/public-api';
import { modulesMap } from '../../common/modules-map'; import { modulesMap } from '../../common/modules-map';
import { DeviceProfileModule } from './device-profile/device-profile.module'; import { DeviceProfileModule } from './device-profile/device-profile.module';
import { ApiUsageModule } from '@home/pages/api-usage/api-usage.module';
@NgModule({ @NgModule({
exports: [ exports: [
@ -50,6 +51,7 @@ import { DeviceProfileModule } from './device-profile/device-profile.module';
WidgetLibraryModule, WidgetLibraryModule,
DashboardModule, DashboardModule,
AuditLogModule, AuditLogModule,
ApiUsageModule,
UserModule UserModule
], ],
providers: [ providers: [

2
ui-ngx/src/app/shared/models/constants.ts

@ -108,6 +108,7 @@ export const HelpLinks = {
ruleNodeRabbitMq: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rabbitmq-node', ruleNodeRabbitMq: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rabbitmq-node',
ruleNodeRestApiCall: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node', ruleNodeRestApiCall: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node',
ruleNodeSendEmail: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node', ruleNodeSendEmail: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node',
ruleNodeSendSms: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-sms-node',
tenants: helpBaseUrl + '/docs/user-guide/ui/tenants', tenants: helpBaseUrl + '/docs/user-guide/ui/tenants',
tenantProfiles: helpBaseUrl + '/docs/user-guide/ui/tenant-profiles', tenantProfiles: helpBaseUrl + '/docs/user-guide/ui/tenant-profiles',
customers: helpBaseUrl + '/docs/user-guide/ui/customers', customers: helpBaseUrl + '/docs/user-guide/ui/customers',
@ -220,5 +221,6 @@ export const contentTypesMap = new Map<ContentType, ContentTypeData>(
); );
export const customTranslationsPrefix = 'custom.'; export const customTranslationsPrefix = 'custom.';
export const i18nPrefix = 'i18n';
export const MODULES_MAP = new InjectionToken<{[key: string]: any}>('ModulesMap'); export const MODULES_MAP = new InjectionToken<{[key: string]: any}>('ModulesMap');

3
ui-ngx/src/app/shared/models/rule-node.models.ts

@ -416,7 +416,8 @@ const ruleNodeClazzHelpLinkMap = {
'org.thingsboard.rule.engine.mqtt.azure.TbAzureIotHubNode': 'ruleNodeAzureIotHub', 'org.thingsboard.rule.engine.mqtt.azure.TbAzureIotHubNode': 'ruleNodeAzureIotHub',
'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode': 'ruleNodeRabbitMq', 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode': 'ruleNodeRabbitMq',
'org.thingsboard.rule.engine.rest.TbRestApiCallNode': 'ruleNodeRestApiCall', 'org.thingsboard.rule.engine.rest.TbRestApiCallNode': 'ruleNodeRestApiCall',
'org.thingsboard.rule.engine.mail.TbSendEmailNode': 'ruleNodeSendEmail' 'org.thingsboard.rule.engine.mail.TbSendEmailNode': 'ruleNodeSendEmail',
'org.thingsboard.rule.engine.sms.TbSendSmsNode': 'ruleNodeSendSms'
}; };
export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): string { export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): string {

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

@ -432,6 +432,9 @@
"no-attributes-text": "No attributes found", "no-attributes-text": "No attributes found",
"no-telemetry-text": "No telemetry found" "no-telemetry-text": "No telemetry found"
}, },
"api-usage": {
"api-usage": "Api Usage"
},
"audit-log": { "audit-log": {
"audit": "Audit", "audit": "Audit",
"audit-logs": "Audit Logs", "audit-logs": "Audit Logs",

Loading…
Cancel
Save