Browse Source

Merge branch 'develop/3.0' of https://github.com/thingsboard/thingsboard into map/3.0

pull/2664/head
Adsumus 7 years ago
parent
commit
8460358f06
  1. 34
      dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
  2. 30
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java
  3. 34
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  4. 12
      dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java
  5. 2
      msa/js-executor/package.json
  6. 2
      msa/web-ui/package.json
  7. 2
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
  8. 3506
      ui-ngx/package-lock.json
  9. 118
      ui-ngx/package.json
  10. 2
      ui-ngx/src/app/modules/home/components/alias/aliases-entity-select-panel.component.html
  11. 4
      ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.html
  12. 10
      ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.html
  13. 14
      ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts
  14. 2
      ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.html
  15. 23
      ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.ts
  16. 38
      ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.html
  17. 6
      ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.scss
  18. 7
      ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts
  19. 8
      ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html
  20. 8
      ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.html
  21. 16
      ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.ts
  22. 1
      ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html
  23. 8
      ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.scss
  24. 8
      ui-ngx/src/app/modules/home/components/dashboard/layout-button.scss
  25. 18
      ui-ngx/src/app/modules/home/components/dashboard/select-target-layout-dialog.component.html
  26. 15
      ui-ngx/src/app/modules/home/components/dashboard/select-target-state-dialog.component.html
  27. 3
      ui-ngx/src/app/modules/home/components/dashboard/select-target-state-dialog.component.ts
  28. 2
      ui-ngx/src/app/modules/home/components/details-panel.component.html
  29. 2
      ui-ngx/src/app/modules/home/components/details-panel.component.scss
  30. 6
      ui-ngx/src/app/modules/home/components/entity/entity-filter-view.component.ts
  31. 12
      ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html
  32. 60
      ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html
  33. 24
      ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss
  34. 16
      ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts
  35. 4
      ui-ngx/src/app/modules/home/components/relation/relation-table.component.html
  36. 2
      ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-editor.component.html
  37. 34
      ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-editor.component.ts
  38. 4
      ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.html
  39. 7
      ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.ts
  40. 16
      ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html
  41. 15
      ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.models.ts
  42. 19
      ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts
  43. 20
      ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html
  44. 20
      ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.scss
  45. 2
      ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts
  46. 10
      ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.html
  47. 1
      ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.scss
  48. 21
      ui-ngx/src/app/modules/home/components/widget/data-key-config.component.html
  49. 22
      ui-ngx/src/app/modules/home/components/widget/data-key-config.component.scss
  50. 5
      ui-ngx/src/app/modules/home/components/widget/data-keys.component.scss
  51. 14
      ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts
  52. 3
      ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts
  53. 1
      ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts
  54. 4
      ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html
  55. 4
      ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html
  56. 4
      ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html
  57. 162
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
  58. 24
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss
  59. 2
      ui-ngx/src/app/modules/home/home.component.ts
  60. 13
      ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.html
  61. 8
      ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.ts
  62. 2
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html
  63. 24
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.html
  64. 20
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-settings-dialog.component.html
  65. 14
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-settings-dialog.component.scss
  66. 2
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-settings-dialog.component.ts
  67. 6
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-toolbar.component.html
  68. 29
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-toolbar.component.scss
  69. 2
      ui-ngx/src/app/modules/home/pages/dashboard/layout/dashboard-layout.component.ts
  70. 3
      ui-ngx/src/app/modules/home/pages/dashboard/layout/layout.models.ts
  71. 27
      ui-ngx/src/app/modules/home/pages/dashboard/layout/manage-dashboard-layouts-dialog.component.html
  72. 11
      ui-ngx/src/app/modules/home/pages/dashboard/layout/manage-dashboard-layouts-dialog.component.ts
  73. 10
      ui-ngx/src/app/modules/home/pages/dashboard/states/dashboard-state-dialog.component.html
  74. 4
      ui-ngx/src/app/modules/home/pages/dashboard/states/dashboard-state-dialog.component.ts
  75. 2
      ui-ngx/src/app/modules/home/pages/dashboard/states/entity-state-controller.component.ts
  76. 30
      ui-ngx/src/app/modules/home/pages/dashboard/states/manage-dashboard-states-dialog.component.html
  77. 8
      ui-ngx/src/app/modules/home/pages/dashboard/states/states-component.directive.ts
  78. 32
      ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html
  79. 7
      ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts
  80. 6
      ui-ngx/src/app/shared/components/color-input.component.scss
  81. 22
      ui-ngx/src/app/shared/components/color-input.component.ts
  82. 31
      ui-ngx/src/app/shared/components/dashboard-autocomplete.component.ts
  83. 2
      ui-ngx/src/app/shared/components/dashboard-select.component.html
  84. 2
      ui-ngx/src/app/shared/components/dialog/todo-dialog.component.ts
  85. 39
      ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts
  86. 11
      ui-ngx/src/app/shared/components/fab-toolbar.component.ts
  87. 1
      ui-ngx/src/app/shared/components/json-form/react/json-form-checkbox.tsx
  88. 7
      ui-ngx/src/app/shared/components/led-light.component.ts
  89. 2
      ui-ngx/src/app/shared/components/logo.component.ts
  90. 2
      ui-ngx/src/app/shared/components/material-icon-select.component.html
  91. 6
      ui-ngx/src/app/shared/components/material-icon-select.component.scss
  92. 24
      ui-ngx/src/app/shared/components/material-icon-select.component.ts
  93. 2
      ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html
  94. 28
      ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts
  95. 8
      ui-ngx/src/app/shared/components/socialshare-panel.component.html
  96. 12
      ui-ngx/src/app/shared/components/socialshare-panel.component.ts
  97. 1
      ui-ngx/src/styles.scss
  98. 18
      ui/src/app/common/types.constant.js
  99. 7
      ui/src/app/components/gateway/gateway-config.directive.js
  100. 12
      ui/src/app/components/gateway/gateway-config.tpl.html

34
dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java

@ -126,18 +126,14 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
log.trace("Executing saveAsset [{}]", asset);
assetValidator.validate(asset, Asset::getTenantId);
Asset savedAsset;
if (!sqlDatabaseUsed) {
try {
savedAsset = assetDao.save(asset.getTenantId(), asset);
} else {
try {
savedAsset = assetDao.save(asset.getTenantId(), asset);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("asset_name_unq_key")) {
throw new DataValidationException("Asset with such name already exists!");
} else {
throw t;
}
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("asset_name_unq_key")) {
throw new DataValidationException("Asset with such name already exists!");
} else {
throw t;
}
}
return savedAsset;
@ -324,26 +320,10 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
@Override
protected void validateCreate(TenantId tenantId, Asset asset) {
if (!sqlDatabaseUsed) {
assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent(
d -> {
throw new DataValidationException("Asset with such name already exists!");
}
);
}
}
@Override
protected void validateUpdate(TenantId tenantId, Asset asset) {
if (!sqlDatabaseUsed) {
assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent(
d -> {
if (!d.getId().equals(asset.getId())) {
throw new DataValidationException("Asset with such name already exists!");
}
}
);
}
}
@Override

30
dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java

@ -80,18 +80,14 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
}
log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials);
credentialsValidator.validate(deviceCredentials, id -> tenantId);
if (!sqlDatabaseUsed) {
try {
return deviceCredentialsDao.save(tenantId, deviceCredentials);
} else {
try {
return deviceCredentialsDao.save(tenantId, deviceCredentials);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_credentials_id_unq_key")) {
throw new DataValidationException("Specified credentials are already registered!");
} else {
throw t;
}
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_credentials_id_unq_key")) {
throw new DataValidationException("Specified credentials are already registered!");
} else {
throw t;
}
}
}
@ -115,12 +111,6 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
@Override
protected void validateCreate(TenantId tenantId, DeviceCredentials deviceCredentials) {
if (!sqlDatabaseUsed) {
DeviceCredentials existingCredentialsEntity = deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId());
if (existingCredentialsEntity != null) {
throw new DataValidationException("Create of existent device credentials!");
}
}
}
@Override
@ -129,12 +119,6 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
if (existingCredentials == null) {
throw new DataValidationException("Unable to update non-existent device credentials!");
}
if (!sqlDatabaseUsed) {
DeviceCredentials sameCredentialsId = deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId());
if (sameCredentialsId != null && !sameCredentialsId.getUuidId().equals(deviceCredentials.getUuidId())) {
throw new DataValidationException("Specified credentials are already registered!");
}
}
}
@Override

34
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -144,18 +144,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
log.trace("Executing saveDevice [{}]", device);
deviceValidator.validate(device, Device::getTenantId);
Device savedDevice;
if (!sqlDatabaseUsed) {
try {
savedDevice = deviceDao.save(device.getTenantId(), device);
} else {
try {
savedDevice = deviceDao.save(device.getTenantId(), device);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) {
throw new DataValidationException("Device with such name already exists!");
} else {
throw t;
}
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) {
throw new DataValidationException("Device with such name already exists!");
} else {
throw t;
}
}
if (device.getId() == null) {
@ -362,26 +358,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
@Override
protected void validateCreate(TenantId tenantId, Device device) {
if (!sqlDatabaseUsed) {
deviceDao.findDeviceByTenantIdAndName(device.getTenantId().getId(), device.getName()).ifPresent(
d -> {
throw new DataValidationException("Device with such name already exists!");
}
);
}
}
@Override
protected void validateUpdate(TenantId tenantId, Device device) {
if (!sqlDatabaseUsed) {
deviceDao.findDeviceByTenantIdAndName(device.getTenantId().getId(), device.getName()).ifPresent(
d -> {
if (!d.getUuidId().equals(device.getUuidId())) {
throw new DataValidationException("Device with such name already exists!");
}
}
);
}
}
@Override

12
dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java

@ -18,12 +18,10 @@ package org.thingsboard.server.dao.entity;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.relation.RelationService;
import javax.annotation.PostConstruct;
import java.util.Optional;
@Slf4j
@ -32,16 +30,6 @@ public abstract class AbstractEntityService {
@Autowired
protected RelationService relationService;
@Value("${database.entities.type:sql}")
private String databaseType;
protected boolean sqlDatabaseUsed;
@PostConstruct
public void init() {
sqlDatabaseUsed = "sql".equalsIgnoreCase(databaseType);
}
protected void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
log.trace("Executing deleteEntityRelations [{}]", entityId);
relationService.deleteEntityRelations(tenantId, entityId);

2
msa/js-executor/package.json

@ -1,7 +1,7 @@
{
"name": "thingsboard-js-executor",
"private": true,
"version": "2.4.3",
"version": "3.0.0",
"description": "ThingsBoard JavaScript Executor Microservice",
"main": "server.js",
"bin": "server.js",

2
msa/web-ui/package.json

@ -1,7 +1,7 @@
{
"name": "thingsboard-web-ui",
"private": true,
"version": "2.4.3",
"version": "3.0.0",
"description": "ThingsBoard Web UI Microservice",
"main": "server.js",
"bin": "server.js",

2
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long

3506
ui-ngx/package-lock.json

File diff suppressed because it is too large

118
ui-ngx/package.json

@ -13,122 +13,122 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^9.0.7",
"@angular/animations": "^9.1.2",
"@angular/cdk": "^9.1.3",
"@angular/common": "^9.0.7",
"@angular/compiler": "^9.0.7",
"@angular/core": "^9.0.7",
"@angular/common": "^9.1.2",
"@angular/compiler": "^9.1.2",
"@angular/core": "^9.1.2",
"@angular/flex-layout": "^9.0.0-beta.29",
"@angular/forms": "^9.0.7",
"@angular/material": "^9.1.3",
"@angular/platform-browser": "^9.0.7",
"@angular/platform-browser-dynamic": "^9.0.7",
"@angular/router": "^9.0.7",
"@angular/forms": "^9.1.2",
"@angular/material": "^9.2.1",
"@angular/platform-browser": "^9.1.2",
"@angular/platform-browser-dynamic": "^9.1.2",
"@angular/router": "^9.1.2",
"@auth0/angular-jwt": "^4.0.0",
"@date-io/date-fns": "^2.4.0",
"@date-io/date-fns": "^2.6.1",
"@flowjs/flow.js": "^2.14.0",
"@flowjs/ngx-flow": "^0.4.3",
"@mat-datetimepicker/core": "^4.0.1",
"@material-ui/core": "^4.9.3",
"@mat-datetimepicker/core": "^4.1.0",
"@material-ui/core": "^4.9.11",
"@material-ui/icons": "^4.9.1",
"@material-ui/pickers": "^3.2.10",
"@ngrx/effects": "^8.6.0",
"@ngrx/store": "^8.6.0",
"@ngrx/store-devtools": "^8.6.0",
"@ngrx/effects": "^9.1.0",
"@ngrx/store": "^9.1.0",
"@ngrx/store-devtools": "^9.1.0",
"@ngx-share/core": "^7.1.4",
"@ngx-translate/core": "^12.1.1",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "^4.0.0",
"ace-builds": "^1.4.8",
"angular-gridster2": "^9.0.1",
"angular2-hotkeys": "^2.1.5",
"ace-builds": "^1.4.11",
"angular-gridster2": "^9.1.0",
"angular2-hotkeys": "^2.2.0",
"base64-js": "^1.3.1",
"canvas-gauges": "^2.1.5",
"canvas-gauges": "^2.1.7",
"compass-sass-mixins": "^0.12.7",
"core-js": "^3.6.4",
"date-fns": "^2.9.0",
"core-js": "^3.6.5",
"date-fns": "^2.12.0",
"flot": "git://github.com/thingsboard/flot.git#0.9-work",
"flot.curvedlines": "git://github.com/MichaelZinsmaier/CurvedLines.git#master",
"font-awesome": "^4.7.0",
"javascript-detect-element-resize": "^0.5.3",
"jquery": "^3.4.1",
"jquery.terminal": "^2.14.0",
"js-beautify": "^1.10.3",
"jquery": "^3.5.0",
"jquery.terminal": "^2.15.4",
"js-beautify": "^1.11.0",
"json-schema-defaults": "^0.4.0",
"jstree": "^3.3.9",
"jstree-bootstrap-theme": "^1.0.1",
"jszip": "^3.2.2",
"jszip": "^3.4.0",
"leaflet": "^1.6.0",
"leaflet-geometryutil": "^0.9.3",
"leaflet-polylinedecorator": "^1.6.0",
"leaflet-providers": "^1.9.1",
"leaflet.gridlayer.googlemutant": "^0.8.0",
"leaflet.gridlayer.googlemutant": "^0.9.0",
"leaflet.markercluster": "^1.4.1",
"material-design-icons": "^3.0.1",
"messageformat": "^2.3.0",
"moment": "^2.24.0",
"ngx-clipboard": "^12.3.1",
"ngx-color-picker": "^9.0.0",
"ngx-daterangepicker-material": "^2.2.0",
"ngx-clipboard": "^13.0.0",
"ngx-color-picker": "^9.1.0",
"ngx-daterangepicker-material": "^3.0.1",
"ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master",
"ngx-hm-carousel": "^2.0.0-rc.1",
"ngx-translate-messageformat-compiler": "^4.5.0",
"ngx-translate-messageformat-compiler": "^4.6.0",
"objectpath": "^2.0.0",
"prop-types": "^15.7.2",
"raphael": "^2.3.0",
"rc-select": "^10.0.0-rc.6",
"react": "^16.12.0",
"react-ace": "^8.0.0",
"react-dom": "^16.12.0",
"react-dropzone": "^10.2.1",
"rc-select": "^10.2.4",
"react": "^16.13.1",
"react-ace": "^8.1.0",
"react-dom": "^16.13.1",
"react-dropzone": "^10.2.2",
"reactcss": "^1.2.3",
"rxjs": "^6.5.4",
"rxjs": "^6.5.5",
"schema-inspector": "1.6.8",
"screenfull": "^5.0.2",
"split.js": "^1.5.11",
"systemjs": "0.21.5",
"tinycolor2": "^1.4.1",
"tooltipster": "^4.2.7",
"tslib": "^1.10.0",
"tslib": "^1.11.1",
"tv4": "^1.3.0",
"typeface-roboto": "^0.0.75",
"zone.js": "~0.10.2"
"zone.js": "~0.10.3"
},
"devDependencies": {
"@angular-builders/custom-webpack": "^9.0.0-beta.7",
"@angular-devkit/build-angular": "^0.900.7",
"@angular/cli": "^9.0.7",
"@angular/compiler-cli": "^9.0.7",
"@angular/language-service": "^9.0.7",
"@angular-builders/custom-webpack": "^9.1.0",
"@angular-devkit/build-angular": "^0.901.1",
"@angular/cli": "^9.1.1",
"@angular/compiler-cli": "^9.1.2",
"@angular/language-service": "^9.1.2",
"@types/canvas-gauges": "^2.1.2",
"@types/flot": "^0.0.31",
"@types/jasmine": "^3.5.5",
"@types/jasmine": "^3.5.10",
"@types/jasminewd2": "^2.0.8",
"@types/jquery": "^3.3.32",
"@types/js-beautify": "^1.8.1",
"@types/jquery": "^3.3.35",
"@types/js-beautify": "^1.8.2",
"@types/jstree": "^3.3.39",
"@types/jszip": "^3.1.7",
"@types/leaflet": "^1.5.9",
"@types/leaflet": "^1.5.12",
"@types/leaflet-polylinedecorator": "^1.6.0",
"@types/lodash": "^4.14.149",
"@types/raphael": "^2.1.30",
"@types/react": "^16.9.20",
"@types/react-dom": "^16.9.5",
"@types/lodash": "^4.14.150",
"@types/raphael": "^2.3.0",
"@types/react": "^16.9.34",
"@types/react-dom": "^16.9.6",
"@types/tinycolor2": "^1.4.2",
"@types/tooltipster": "^0.0.29",
"codelyzer": "^5.2.1",
"codelyzer": "^5.2.2",
"compression-webpack-plugin": "^3.1.0",
"directory-tree": "^2.2.4",
"jasmine-core": "^3.5.0",
"jasmine-spec-reporter": "^4.2.1",
"karma": "^4.4.1",
"jasmine-spec-reporter": "^5.0.1",
"karma": "^5.0.2",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^2.1.1",
"karma-jasmine": "^3.1.1",
"karma-jasmine-html-reporter": "^1.5.2",
"karma-jasmine-html-reporter": "^1.5.3",
"ngrx-store-freeze": "^0.2.4",
"protractor": "^5.4.3",
"ts-node": "^8.6.2",
"tslint": "^6.0.0",
"protractor": "^5.4.4",
"ts-node": "^8.9.0",
"tslint": "^6.1.1",
"typescript": "~3.7.5"
}
}

2
ui-ngx/src/app/modules/home/components/alias/aliases-entity-select-panel.component.html

@ -19,7 +19,7 @@
<div fxLayout="row" *ngFor="let alias of entityAliasesInfo | keyvalue">
<mat-form-field>
<mat-label>{{alias.value.alias}}</mat-label>
<mat-select matInput [(ngModel)]="alias.value.selectedId"
<mat-select [(ngModel)]="alias.value.selectedId"
(ngModelChange)="currentAliasEntityChanged(alias.key, alias.value.selectedId)">
<mat-option *ngFor="let resolvedEntity of alias.value.resolvedEntities" [value]="resolvedEntity.id">
{{resolvedEntity.name}}

4
ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.html

@ -16,14 +16,14 @@
-->
<section class="tb-aliases-entity-select" fxLayout="row" fxLayoutAlign="start center">
<button mat-button mat-icon-button
<button mat-icon-button
cdkOverlayOrigin #aliasEntitySelectPanelOrigin="cdkOverlayOrigin"
(click)="openEditMode()"
matTooltip="{{ 'entity.select-entities' | translate }}"
[matTooltipPosition]="tooltipPosition">
<mat-icon class="material-icons">devices_other</mat-icon>
</button>
<span fxHide.xs fxHide.sm fxHide.md
<span fxHide.lt-lg
(click)="openEditMode()"
matTooltip="{{ 'entity.select-entities' | translate }}"
[matTooltipPosition]="tooltipPosition">

10
ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.html

@ -15,11 +15,11 @@
limitations under the License.
-->
<form #entityAliasForm="ngForm" [formGroup]="entityAliasFormGroup" (ngSubmit)="save()" style="min-width: 550px;">
<form #entityAliasForm="ngForm" [formGroup]="entityAliasFormGroup" (ngSubmit)="save()" style="min-width: 480px;">
<mat-toolbar color="primary">
<h2>{{ (isAdd ? 'alias.add' : 'alias.edit') | translate }}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
@ -58,15 +58,13 @@
</div>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || entityAliasFormGroup.invalid || !entityAliasFormGroup.dirty">
{{ (isAdd ? 'action.add' : 'action.save') | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

14
ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts

@ -20,26 +20,22 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
AbstractControl,
FormArray,
FormBuilder,
FormControl,
FormGroup,
FormGroupDirective,
NgForm, Validators, ValidatorFn
NgForm,
ValidatorFn,
Validators
} from '@angular/forms';
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { AttributeData } from '@shared/models/telemetry/telemetry.models';
import { EntityAlias, EntityAliases, EntityAliasFilter } from '@shared/models/alias.models';
import { DatasourceType, Widget, widgetType } from '@shared/models/widget.models';
import { EntityAlias, EntityAliases } from '@shared/models/alias.models';
import { AliasEntityType, EntityType } from '@shared/models/entity-type.models';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import { DialogService } from '@core/services/dialog.service';
import { EntityService } from '@core/http/entity.service';
import { Observable, of } from 'rxjs';
import { Observable } from 'rxjs';
export interface EntityAliasDialogData {
isAdd: boolean;

2
ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.html

@ -27,7 +27,7 @@
[matAutocomplete]="entityAliasAutocomplete">
<button *ngIf="selectEntityAliasFormGroup.get('entityAlias').value && !disabled"
type="button"
matSuffix mat-button mat-icon-button aria-label="Clear"
matSuffix mat-icon-button aria-label="Clear"
(click)="clear()">
<mat-icon class="material-icons">close</mat-icon>
</button>

23
ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.ts

@ -21,24 +21,23 @@ import {
FormControl,
FormGroup,
FormGroupDirective,
NG_VALUE_ACCESSOR, NgForm
NG_VALUE_ACCESSOR,
NgForm
} from '@angular/forms';
import { Observable, of } from 'rxjs';
import { map, mergeMap, startWith, tap, share, filter } from 'rxjs/operators';
import {Store} from '@ngrx/store';
import {AppState} from '@app/core/core.state';
import {TranslateService} from '@ngx-translate/core';
import {AliasEntityType, EntityType} from '@shared/models/entity-type.models';
import {BaseData} from '@shared/models/base-data';
import {EntityId} from '@shared/models/id/entity-id';
import {EntityService} from '@core/http/entity.service';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import { map, mergeMap, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { EntityType } from '@shared/models/entity-type.models';
import { EntityService } from '@core/http/entity.service';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { EntityAlias } from '@shared/models/alias.models';
import { IAliasController } from '@core/api/widget-api.models';
import { TruncatePipe } from '@shared/pipe/truncate.pipe';
import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { MatAutocomplete, MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { EntityAliasSelectCallbacks } from './entity-alias-select.component.models';
import {ENTER} from '@angular/cdk/keycodes';
import { ENTER } from '@angular/cdk/keycodes';
import { ErrorStateMatcher } from '@angular/material/core';
@Component({

38
ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.html

@ -16,10 +16,10 @@
-->
<form #entityAliasesForm="ngForm" [formGroup]="entityAliasesFormGroup" (ngSubmit)="save()" style="width: 700px;">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2>{{ title | translate }}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
@ -28,18 +28,18 @@
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<div class="tb-aliases-header" fxFlex fxLayout="row" fxLayoutAlign="start center">
<span fxFlex="5"></span>
<div fxFlex="95" fxLayout="row" fxLayoutAlign="start center">
<span class="tb-header-label" translate fxFlex="150px">alias.name</span>
<span class="tb-header-label" translate fxFlex style="padding-left: 10px;">alias.entity-filter</span>
<span class="tb-header-label" translate fxFlex="120px" style="padding-left: 10px;">alias.resolve-multiple</span>
<span style="min-width: 80px;"></span>
</div>
</div>
<mat-divider></mat-divider>
<div mat-dialog-content>
<div class="tb-aliases-header" fxLayout="row" fxLayoutAlign="start center">
<span fxFlex="5"></span>
<div fxFlex="95" fxLayout="row" fxLayoutAlign="start center">
<span class="tb-header-label" translate fxFlex="150px">alias.name</span>
<span class="tb-header-label" translate fxFlex style="padding-left: 10px;">alias.entity-filter</span>
<span class="tb-header-label" translate fxFlex="120px" style="padding-left: 10px;">alias.resolve-multiple</span>
<span style="min-width: 80px;"></span>
</div>
</div>
<fieldset [disabled]="isLoading$ | async">
<mat-divider></mat-divider>
<div fxFlex fxLayout="row" fxLayoutAlign="start center"
formArrayName="entityAliases"
*ngFor="let entityAliasControl of entityAliasesFormArray().controls; let $index = index">
@ -63,7 +63,7 @@
</mat-slide-toggle>
</section>
<button [disabled]="isLoading$ | async"
mat-button mat-icon-button color="primary"
mat-icon-button color="primary"
style="min-width: 40px;"
type="button"
(click)="editAlias($index)"
@ -72,7 +72,7 @@
<mat-icon>edit</mat-icon>
</button>
<button [disabled]="isLoading$ | async"
mat-button mat-icon-button color="primary"
mat-icon-button color="primary"
style="min-width: 40px;"
type="button"
(click)="removeAlias($index)"
@ -84,8 +84,8 @@
</div>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions>
<button mat-raised-button color="primary"
type="button"
(click)="addAlias()"
[fxShow]="!disableAdd"
@ -95,16 +95,16 @@
{{ 'alias.add' | translate }}
</button>
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || entityAliasesFormGroup.invalid || !entityAliasesFormGroup.dirty">
{{ 'action.save' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
(click)="cancel()"
cdkFocusInitial>
{{ 'action.cancel' | translate }}
</button>
</div>

6
ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.scss

@ -17,7 +17,7 @@
.tb-aliases-header {
min-height: 40px;
padding: 0 34px 0 34px;
padding: 0 11px;
margin: 5px;
.tb-header-label {
@ -26,6 +26,10 @@
}
}
mat-divider{
margin: -1px -24px;
}
.tb-alias {
padding: 0 0 0 10px;
margin: 5px;

7
ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts

@ -16,7 +16,7 @@
import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
@ -26,11 +26,11 @@ import {
FormControl,
FormGroup,
FormGroupDirective,
NgForm, Validators
NgForm,
Validators
} from '@angular/forms';
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { AttributeData } from '@shared/models/telemetry/telemetry.models';
import { EntityAlias, EntityAliases, EntityAliasFilter } from '@shared/models/alias.models';
import { DatasourceType, Widget, widgetType } from '@shared/models/widget.models';
import { AliasEntityType, EntityType } from '@shared/models/entity-type.models';
@ -39,7 +39,6 @@ import { TranslateService } from '@ngx-translate/core';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import { DialogService } from '@core/services/dialog.service';
import { deepClone, isUndefined } from '@core/utils';
import { MatDialog } from '@angular/material/dialog';
import { EntityAliasDialogComponent, EntityAliasDialogData } from './entity-alias-dialog.component';
export interface EntityAliasesDialogData {

8
ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html

@ -16,7 +16,7 @@
-->
<form [formGroup]="attributeFormGroup" (ngSubmit)="add()" style="min-width: 400px;">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2>{{ 'attribute.add' | translate }}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -43,15 +43,13 @@
</tb-value-input>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || attributeFormGroup.invalid || !attributeFormGroup.dirty">
{{ 'action.add' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

8
ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.html

@ -16,7 +16,7 @@
-->
<form #addWidgetForm="ngForm" [formGroup]="addWidgetFormGroup" (ngSubmit)="add()" style="min-width: 400px;">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2 translate>attribute.add-widget-to-dashboard</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -55,19 +55,17 @@
</mat-radio-group>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<div mat-dialog-actions fxLayoutAlign="end center">
<mat-checkbox formControlName="openDashboard"
style="margin-bottom: 0px; padding-right: 20px;">
{{ 'dashboard.open-dashboard' | translate }}
</mat-checkbox>
<button mat-button mat-raised-button color="primary"
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || addWidgetFormGroup.invalid || !addWidgetFormGroup.dirty">
{{ 'action.add' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

16
ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.ts

@ -16,34 +16,26 @@
import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import {
DashboardLayoutId,
DashboardSettings,
GridSettings,
StateControllerId,
Dashboard
} from '@app/shared/models/dashboard.models';
import { isUndefined, objToBase64 } from '@core/utils';
import { Dashboard, DashboardLayoutId } from '@app/shared/models/dashboard.models';
import { objToBase64 } from '@core/utils';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import { EntityId } from '@app/shared/models/id/entity-id';
import { Widget } from '@app/shared/models/widget.models';
import { DashboardService } from '@core/http/dashboard.service';
import { forkJoin, Observable, of } from 'rxjs';
import { SelectTargetLayoutDialogComponent } from '@home/components/dashboard/select-target-layout-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import {
SelectTargetStateDialogComponent,
SelectTargetStateDialogData
} from '@home/components/dashboard/select-target-state-dialog.component';
import { mergeMap, map } from 'rxjs/operators';
import { mergeMap } from 'rxjs/operators';
import { AliasesInfo } from '@shared/models/alias.models';
import { ItemBufferService } from '@core/services/item-buffer.service';
import { StateObject } from '@core/api/widget-api.models';

1
ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html

@ -83,6 +83,7 @@
<div fxLayout="row" fxLayoutAlign="space-between start">
<div class="tb-widget-title" fxLayout="column" fxLayoutAlign="center start" [fxShow]="widget.showWidgetTitlePanel">
<span [fxShow]="widget.showTitle"
[ngClass]="{'single-row': widget.hasTimewindow}"
[ngStyle]="widget.titleStyle"
[matTooltip]="widget.titleTooltip"
matTooltipClass="tb-tooltip-multiline"

8
ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.scss

@ -76,6 +76,7 @@ div.tb-widget {
tb-timewindow {
font-size: 14px;
opacity: .85;
margin: 0;
}
.title {
@ -85,6 +86,13 @@ div.tb-widget {
line-height: 24px;
letter-spacing: .01em;
margin: 0;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
&.single-row{
-webkit-line-clamp: 1;
}
}
}

8
ui-ngx/src/app/modules/home/components/dashboard/layout-button.scss

@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host ::ng-deep {
:host {
button.tb-layout-button {
width: 100%;
max-width: 240px;
height: 100%;
padding: 40px 20px;
}
&::ng-deep {
.mat-button-wrapper {
padding: 40px;
line-height: 18px;
span {
font-size: 18px;

18
ui-ngx/src/app/modules/home/components/dashboard/select-target-layout-dialog.component.html

@ -16,10 +16,10 @@
-->
<form #widgetForm="ngForm">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2 translate>layout.select</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
@ -30,16 +30,18 @@
<div mat-dialog-content>
<fieldset [disabled]="isLoading$ | async" fxLayout="column" fxLayoutGap="8px">
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<button fxFlex fxLayout="column"
type="button" mat-button mat-raised-button color="primary"
<button fxFlex
mat-raised-button color="primary"
type="button"
class="tb-layout-button"
(click)="selectLayout('main')">
(click)="selectLayout('main')">
<span translate>layout.main</span>
</button>
<button fxFlex fxLayout="column"
type="button" mat-button mat-raised-button color="primary"
<button fxFlex
mat-raised-button color="primary"
type="button"
class="tb-layout-button"
(click)="selectLayout('right')">
(click)="selectLayout('right')">
<span translate>layout.right</span>
</button>
</div>

15
ui-ngx/src/app/modules/home/components/dashboard/select-target-state-dialog.component.html

@ -16,10 +16,10 @@
-->
<form #stateForm="ngForm" [formGroup]="stateFormGroup" (ngSubmit)="save()">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2 translate>dashboard.select-state</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
@ -31,7 +31,7 @@
<fieldset [disabled]="isLoading$ | async" fxLayout="column">
<mat-form-field class="mat-block">
<mat-label translate>dashboard.state</mat-label>
<mat-select required matInput formControlName="stateId">
<mat-select required formControlName="stateId">
<mat-option *ngFor="let stateItem of states | keyvalue" [value]="stateItem.key">
{{ stateItem.value.name }}
</mat-option>
@ -39,18 +39,17 @@
</mat-form-field>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || stateFormGroup.invalid">
{{ 'action.select' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
(click)="cancel()"
cdkFocusInitial>
{{ 'action.cancel' | translate }}
</button>
</div>

3
ui-ngx/src/app/modules/home/components/dashboard/select-target-state-dialog.component.ts

@ -22,11 +22,8 @@ import { AppState } from '@core/core.state';
import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { DashboardState } from '@app/shared/models/dashboard.models';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import { DashboardService } from '@core/http/dashboard.service';
export interface SelectTargetStateDialogData {
states: {[id: string]: DashboardState };

2
ui-ngx/src/app/modules/home/components/details-panel.component.html

@ -17,7 +17,7 @@
-->
<header>
<mat-toolbar class="details-toolbar" color="primary" [ngStyle]="{height: headerHeightPx+'px'}">
<div class="mat-toolbar-tools" fxFlex fxLayout="row" fxLayoutAlign="start center" style="height: 100%;">
<div class="mat-toolbar-tools" fxLayout="row" fxLayoutAlign="start center" style="height: 100%;">
<div class="mat-toolbar-tools tb-details-title-header" fxFlex fxLayout="column" fxLayoutAlign="start start">
<span class="tb-details-title">{{ headerTitle }}</span>
<span class="tb-details-subtitle">{{ headerSubtitle }}</span>

2
ui-ngx/src/app/modules/home/components/details-panel.component.scss

@ -45,7 +45,7 @@
white-space: nowrap;
@media #{$mat-gt-sm} {
font-size: 1.6rem;
font-size: 1.5rem;
}
}

6
ui-ngx/src/app/modules/home/components/entity/entity-filter-view.component.ts

@ -102,14 +102,14 @@ export class EntityFilterViewComponent implements ControlValueAccessor {
}
break;
case AliasFilterType.entityViewType:
const entityViewType = this.filter.entityViewType;
const entityView = this.filter.entityViewType;
prefix = this.filter.entityViewNameFilter;
if (prefix && prefix.length) {
this.filterDisplayValue = this.translate.instant('alias.filter-type-entity-view-type-and-name-description',
{entityViewType, prefix});
{entityView, prefix});
} else {
this.filterDisplayValue = this.translate.instant('alias.filter-type-entity-view-type-description',
{entityViewType});
{entityView});
}
break;
case AliasFilterType.relationsQuery:

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

@ -141,10 +141,10 @@
<label class="tb-small root-state-entity-label" translate>alias.last-level-relation</label>
</section>
</div>
<div fxFlex fxLayoutGap="8px" fxLayout="row">
<div fxFlex fxLayoutGap="8px" fxLayout="row" fxLayout.xs="column">
<mat-form-field class="mat-block" style="min-width: 100px;">
<mat-label translate>relation.direction</mat-label>
<mat-select required matInput formControlName="direction">
<mat-select required formControlName="direction">
<mat-option *ngFor="let type of directionTypes" [value]="type">
{{ directionTypeTranslations.get(directionTypeEnum[type]) | translate }}
</mat-option>
@ -172,7 +172,7 @@
entityFilterFormGroup.get('type').value === aliasFilterType.entityViewSearchQuery ?
entityFilterFormGroup.get('type').value : ''">
<label class="tb-small">{{ 'alias.root-entity' | translate }}</label>
<section class="tb-root-state-entity-switch" fxLayout="row" fxLayoutAlign="start center" style="padding-left: 0px;">
<section class="tb-root-state-entity-switch" fxLayout="row" fxLayoutAlign="start center" style="padding-left: 0;">
<mat-slide-toggle class="root-state-entity-switch"
formControlName="rootStateEntity">
</mat-slide-toggle>
@ -200,17 +200,17 @@
</div>
</div>
<div fxFlex fxLayout="row">
<section class="tb-root-state-entity-switch" fxLayout="row" fxLayoutAlign="start center" style="padding-left: 0px;">
<section class="tb-root-state-entity-switch" fxLayout="row" fxLayoutAlign="start center" style="padding-left: 0;">
<mat-slide-toggle class="root-state-entity-switch"
formControlName="fetchLastLevelOnly">
</mat-slide-toggle>
<label class="tb-small root-state-entity-label" translate>alias.last-level-relation</label>
</section>
</div>
<div fxFlex fxLayoutGap="8px" fxLayout="row">
<div fxFlex fxLayoutGap="8px" fxLayout="row" fxLayout.xs="column">
<mat-form-field class="mat-block" style="min-width: 100px;">
<mat-label translate>relation.direction</mat-label>
<mat-select required matInput formControlName="direction">
<mat-select required formControlName="direction">
<mat-option *ngFor="let type of directionTypes" [value]="type">
{{ directionTypeTranslations.get(directionTypeEnum[type]) | translate }}
</mat-option>

60
ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html

@ -16,35 +16,37 @@
-->
<div class="tb-relation-filters" [formGroup]="relationFiltersFormGroup">
<div class="header" [fxShow]="relationFiltersFormArray().length">
<div fxLayout="row" fxLayoutAlign="start center">
<span class="cell" style="width: 200px; min-width: 200px;" translate>relation.type</span>
<span class="cell" fxFlex translate>entity.entity-types</span>
<span class="cell" style="width: 40px; min-width: 40px;">&nbsp;</span>
<div class="container">
<div class="header" [fxShow]="relationFiltersFormArray().length">
<div fxLayout="row" fxLayoutAlign="start center">
<span class="cell" style="width: 200px; min-width: 200px;" translate>relation.type</span>
<span class="cell" fxFlex translate>entity.entity-types</span>
<span class="cell" style="width: 40px; min-width: 40px;">&nbsp;</span>
</div>
</div>
</div>
<div class="body" [fxShow]="relationFiltersFormArray().length">
<div class="row" fxFlex fxLayout="row"
fxLayoutAlign="start center" formArrayName="relationFilters"
*ngFor="let relationFilterControl of relationFiltersFormArray().controls; let $index = index">
<div class="mat-elevation-z1" fxFlex fxLayout="row" fxLayoutAlign="start center">
<tb-relation-type-autocomplete
class="cell" style="width: 200px; min-width: 200px;"
[formControl]="relationFilterControl.get('relationType')">
</tb-relation-type-autocomplete>
<tb-entity-type-list class="cell" fxFlex
[allowedEntityTypes]="allowedEntityTypes"
[formControl]="relationFilterControl.get('entityTypes')">
</tb-entity-type-list>
<button mat-button mat-icon-button color="primary"
type="button"
style="width: 40px; min-width: 40px;"
(click)="removeFilter($index)"
[disabled]="isLoading$ | async"
matTooltip="{{ 'relation.remove-relation-filter' | translate }}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
<div class="body" [fxShow]="relationFiltersFormArray().length">
<div class="row" fxFlex fxLayout="row"
fxLayoutAlign="start center" formArrayName="relationFilters"
*ngFor="let relationFilterControl of relationFiltersFormArray().controls; let $index = index">
<div class="mat-elevation-z1" fxFlex fxLayout="row" fxLayoutAlign="start center">
<tb-relation-type-autocomplete
class="cell" style="width: 200px; min-width: 200px;"
[formControl]="relationFilterControl.get('relationType')">
</tb-relation-type-autocomplete>
<tb-entity-type-list class="cell" fxFlex
[allowedEntityTypes]="allowedEntityTypes"
[formControl]="relationFilterControl.get('entityTypes')">
</tb-entity-type-list>
<button mat-icon-button color="primary"
type="button"
style="width: 40px; min-width: 40px;"
(click)="removeFilter($index)"
[disabled]="isLoading$ | async"
matTooltip="{{ 'relation.remove-relation-filter' | translate }}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</div>
</div>
@ -53,7 +55,7 @@
class="tb-prompt" translate>relation.any-relation</span>
</div>
<div>
<button mat-button mat-raised-button color="primary"
<button mat-raised-button color="primary"
[disabled]="isLoading$ | async"
(click)="addFilter()"
type="button"

24
ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss

@ -15,10 +15,17 @@
*/
:host {
.tb-relation-filters {
max-width: calc(100vw - 48px);
overflow: hidden;
.container{
width: 100%;
overflow: auto;
}
.header {
padding-right: 5px;
padding-bottom: 5px;
padding-left: 5px;
width: max-content;
padding: 0 5px 5px;
.cell {
padding-right: 5px;
@ -31,11 +38,8 @@
}
.body {
max-height: 300px;
padding-right: 5px;
padding-bottom: 20px;
padding-left: 5px;
overflow: auto;
width: max-content;
padding: 0 5px 20px;
.row {
padding-top: 5px;
@ -46,6 +50,10 @@
padding-left: 5px;
}
}
.any-filter{
margin: 10px 0 20px;
}
}
}

16
ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts

@ -14,21 +14,17 @@
/// limitations under the License.
///
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor, FormArray,
FormBuilder, FormControl,
ControlValueAccessor,
FormArray,
FormBuilder,
FormGroup,
NG_VALUE_ACCESSOR,
ValidatorFn,
Validators
NG_VALUE_ACCESSOR
} from '@angular/forms';
import { AliasFilterType, aliasFilterTypeTranslationMap, EntityAliasFilter } from '@shared/models/alias.models';
import { AliasEntityType, EntityType } from '@shared/models/entity-type.models';
import { TranslateService } from '@ngx-translate/core';
import { EntityService } from '@core/http/entity.service';
import { EntitySearchDirection, entitySearchDirectionTranslations, EntityTypeFilter } from '@shared/models/relation.models';
import { EntityTypeFilter } from '@shared/models/relation.models';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';

4
ui-ngx/src/app/modules/home/components/relation/relation-table.component.html

@ -86,7 +86,7 @@
</div>
</mat-toolbar>
<div fxFlex class="table-container">
<mat-table [dataSource]="dataSource"
<table mat-table [dataSource]="dataSource"
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
<ng-container matColumnDef="select" sticky>
<mat-header-cell *matHeaderCellDef style="width: 30px;">
@ -156,7 +156,7 @@
<mat-row [ngClass]="{'mat-row-select': true,
'mat-selected': dataSource.selection.isSelected(relation)}"
*matRowDef="let relation; columns: displayedColumns;" (click)="dataSource.selection.toggle(relation)"></mat-row>
</mat-table>
</table>
<span [fxShow]="dataSource.isEmpty() | async"
fxLayoutAlign="center center"
class="no-data-found" translate>{{ 'relation.no-relations-text' }}</span>

2
ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-editor.component.html

@ -17,7 +17,7 @@
-->
<div class="tb-custom-action-pretty mat-elevation-z1" tb-fullscreen [fullscreen]="fullscreen">
<div fxLayout="row" fxLayoutAlign="end center" class="tb-action-expand-button" [ngClass]="{'tb-fullscreen-editor': fullscreen}">
<button mat-button fxHide.xs fxHide.sm
<button mat-button fxHide.lt-md
matTooltip="{{ 'widget.toggle-fullscreen' | translate }}"
matTooltipPosition="above"
(click)="fullscreen = !fullscreen">

34
ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-editor.component.ts

@ -19,46 +19,22 @@
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ElementRef,
forwardRef,
Input,
OnDestroy,
OnInit,
ViewChild, ViewEncapsulation, ViewChildren, QueryList, ComponentFactoryResolver
QueryList,
ViewChildren,
ViewEncapsulation
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { MatDialog } from '@angular/material/dialog';
import { DialogService } from '@core/services/dialog.service';
import { PageLink } from '@shared/models/page/page-link';
import { Direction, SortOrder } from '@shared/models/page/sort-order';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { combineLatest, fromEvent, merge } from 'rxjs';
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
import {
WidgetActionDescriptorInfo,
WidgetActionsData,
WidgetActionsDatasource,
WidgetActionCallbacks, toWidgetActionDescriptor
} from '@home/components/widget/action/manage-widget-actions.component.models';
import { UtilsService } from '@core/services/utils.service';
import { EntityRelation, EntitySearchDirection, RelationTypeGroup } from '@shared/models/relation.models';
import { RelationDialogComponent, RelationDialogData } from '@home/components/relation/relation-dialog.component';
import { CustomActionDescriptor, WidgetActionDescriptor, WidgetActionSource } from '@shared/models/widget.models';
import {
WidgetActionDialogComponent,
WidgetActionDialogData
} from '@home/components/widget/action/widget-action-dialog.component';
import { deepClone } from '@core/utils';
import { TbAnchorComponent } from '@shared/components/tb-anchor.component';
import { CustomActionPrettyResourcesTabsComponent } from '@home/components/widget/action/custom-action-pretty-resources-tabs.component';
import { MatTab, MatTabGroup } from '@angular/material/tabs';
import { combineLatest } from 'rxjs';
import { CustomActionDescriptor } from '@shared/models/widget.models';
@Component({
selector: 'tb-custom-action-pretty-editor',

4
ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.html

@ -23,12 +23,12 @@
fxLayoutAlign="start center"
*ngFor="let resource of action.customResources; let i = index" >
<mat-form-field fxFlex class="mat-block resource-field" floatLabel="never"
style="margin: 10px 0px 0px 0px; max-height: 40px;">
style="margin: 10px 0 0; max-height: 40px;">
<input required matInput [(ngModel)]="resource.url"
(ngModelChange)="notifyActionUpdated()"
placeholder="{{ 'widget.resource-url' | translate }}"/>
</mat-form-field>
<button mat-button mat-icon-button color="primary"
<button mat-icon-button color="primary"
[disabled]="isLoading$ | async"
type="button"
(click)="removeResource(i)"

7
ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.ts

@ -22,9 +22,10 @@ import {
OnChanges,
OnDestroy,
OnInit,
Output, QueryList,
Output,
SimpleChanges,
ViewChild, ViewChildren, ViewEncapsulation
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { PageComponent } from '@shared/components/page.component';
@ -34,8 +35,6 @@ import { CustomActionDescriptor } from '@shared/models/widget.models';
import * as ace from 'ace-builds';
import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
import { css_beautify, html_beautify } from 'js-beautify';
import { MatTab } from '@angular/material/tabs';
import { BehaviorSubject } from 'rxjs';
@Component({
selector: 'tb-custom-action-pretty-resources-tabs',

16
ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html

@ -21,14 +21,14 @@
<div class="mat-toolbar-tools">
<span class="tb-entity-table-title" translate>widget-config.actions</span>
<span fxFlex></span>
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
<button mat-icon-button [disabled]="isLoading$ | async"
type="button"
(click)="addAction($event)"
matTooltip="{{ 'widget-config.add-action' | translate }}"
matTooltipPosition="above">
<mat-icon>add</mat-icon>
</button>
<button mat-button mat-icon-button [disabled]="isLoading$ | async" (click)="enterFilterMode()"
<button mat-icon-button [disabled]="isLoading$ | async" (click)="enterFilterMode()"
type="button"
matTooltip="{{ 'action.search' | translate }}"
matTooltipPosition="above">
@ -38,7 +38,7 @@
</mat-toolbar>
<mat-toolbar class="mat-table-toolbar" [fxShow]="textSearchMode">
<div class="mat-toolbar-tools">
<button mat-button mat-icon-button
<button mat-icon-button
type="button"
matTooltip="{{ 'widget-config.search-actions' | translate }}"
matTooltipPosition="above">
@ -50,7 +50,7 @@
[(ngModel)]="pageLink.textSearch"
placeholder="{{ 'widget-config.search-actions' | translate }}"/>
</mat-form-field>
<button mat-button mat-icon-button (click)="exitFilterMode()"
<button mat-icon-button (click)="exitFilterMode()"
type="button"
matTooltip="{{ 'action.close' | translate }}"
matTooltipPosition="above">
@ -59,7 +59,7 @@
</div>
</mat-toolbar>
<div fxFlex class="table-container">
<mat-table [dataSource]="dataSource"
<table mat-table [dataSource]="dataSource"
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
<ng-container matColumnDef="actionSourceName">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 20%"> {{ 'widget-config.action-source' | translate }} </mat-header-cell>
@ -90,14 +90,14 @@
</mat-header-cell>
<mat-cell *matCellDef="let action">
<div fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
<button mat-icon-button [disabled]="isLoading$ | async"
type="button"
matTooltip="{{ 'widget-config.edit-action' | translate }}"
matTooltipPosition="above"
(click)="editAction($event, action)">
<mat-icon>edit</mat-icon>
</button>
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
<button mat-icon-button [disabled]="isLoading$ | async"
type="button"
matTooltip="{{ 'widget-config.delete-action' | translate }}"
matTooltipPosition="above"
@ -110,7 +110,7 @@
<mat-header-row [ngClass]="{'mat-row-select': true}" *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row [ngClass]="{'mat-row-select': true}"
*matRowDef="let action; columns: displayedColumns;"></mat-row>
</mat-table>
</table>
<span [fxShow]="dataSource.isEmpty() | async"
fxLayoutAlign="center center"
class="no-data-found" translate>{{ 'widget-config.no-actions-text' }}</span>

15
ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.models.ts

@ -14,19 +14,18 @@
/// limitations under the License.
///
import { WidgetActionDescriptor, WidgetActionSource,
widgetActionTypeTranslationMap, CustomActionDescriptor } from '@app/shared/models/widget.models';
import {
CustomActionDescriptor,
WidgetActionDescriptor,
WidgetActionSource,
widgetActionTypeTranslationMap
} from '@app/shared/models/widget.models';
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { EntityRelationInfo, EntitySearchDirection } from '@shared/models/relation.models';
import { BehaviorSubject, Observable, of, ReplaySubject } from 'rxjs';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { SelectionModel } from '@angular/cdk/collections';
import { EntityRelationService } from '@core/http/entity-relation.service';
import { TranslateService } from '@ngx-translate/core';
import { EntityId } from '@shared/models/id/entity-id';
import { PageLink } from '@shared/models/page/page-link';
import { catchError, map, publishReplay, refCount, share, take, tap } from 'rxjs/operators';
import { entityTypeTranslations } from '@shared/models/entity-type.models';
import { catchError, map, publishReplay, refCount } from 'rxjs/operators';
import { UtilsService } from '@core/services/utils.service';
import { deepClone, isDefined, isUndefined } from '@core/utils';

19
ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts

@ -14,17 +14,7 @@
/// limitations under the License.
///
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ElementRef,
forwardRef,
Input,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { PageComponent } from '@shared/components/page.component';
@ -39,14 +29,13 @@ import { MatSort } from '@angular/material/sort';
import { fromEvent, merge } from 'rxjs';
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
import {
toWidgetActionDescriptor,
WidgetActionCallbacks,
WidgetActionDescriptorInfo,
WidgetActionsData,
WidgetActionsDatasource,
WidgetActionCallbacks, toWidgetActionDescriptor
WidgetActionsDatasource
} from '@home/components/widget/action/manage-widget-actions.component.models';
import { UtilsService } from '@core/services/utils.service';
import { EntityRelation, EntitySearchDirection, RelationTypeGroup } from '@shared/models/relation.models';
import { RelationDialogComponent, RelationDialogData } from '@home/components/relation/relation-dialog.component';
import { WidgetActionDescriptor, WidgetActionSource } from '@shared/models/widget.models';
import {
WidgetActionDialogComponent,

20
ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<form #widgetActionForm="ngForm" [formGroup]="widgetActionFormGroup" (ngSubmit)="save()" style="min-width: 600px;">
<mat-toolbar fxLayout="row" color="primary">
<form #widgetActionForm="ngForm" [formGroup]="widgetActionFormGroup" (ngSubmit)="save()" style="min-width: 480px;">
<mat-toolbar color="primary">
<h2>{{ (isAdd ? 'widget-config.add-action' : 'widget-config.edit-action' ) | translate }}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -32,7 +32,7 @@
<fieldset [disabled]="isLoading$ | async">
<mat-form-field class="mat-block">
<mat-label translate>widget-config.action-source</mat-label>
<mat-select required matInput formControlName="actionSourceId">
<mat-select required formControlName="actionSourceId">
<mat-option *ngFor="let actionSourceItem of data.actionsData.actionSources | keyvalue" [value]="actionSourceItem.key">
{{ actionSourceName(actionSourceItem.value) }}
</mat-option>
@ -41,7 +41,7 @@
{{ 'widget-config.action-source-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block" style="padding-bottom: 20px;">
<mat-form-field class="mat-block">
<mat-label translate>widget-config.action-name</mat-label>
<input required matInput formControlName="name">
<mat-error *ngIf="widgetActionFormGroup.get('name').hasError('required')">
@ -56,7 +56,7 @@
</tb-material-icon-select>
<mat-form-field class="mat-block">
<mat-label translate>widget-config.action-type</mat-label>
<mat-select required matInput formControlName="type">
<mat-select required formControlName="type">
<mat-option *ngFor="let actionType of widgetActionTypes" [value]="actionType">
{{ widgetActionTypeTranslations.get(widgetActionType[actionType]) | translate }}
</mat-option>
@ -67,7 +67,7 @@
</mat-form-field>
<section fxLayout="column" [formGroup]="actionTypeFormGroup" [ngSwitch]="widgetActionFormGroup.get('type').value">
<ng-template [ngSwitchCase]="widgetActionType.openDashboard">
<div fxLayout="column" style="padding-bottom: 20px;">
<div fxLayout="column">
<div class="mat-caption tb-required"
style="padding-left: 3px; padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate>widget-action.target-dashboard</div>
<tb-dashboard-autocomplete
@ -89,7 +89,7 @@
[matAutocomplete]="targetDashboardStateAutocomplete">
<button *ngIf="actionTypeFormGroup.get('targetDashboardStateId').value"
type="button"
matSuffix mat-button mat-icon-button aria-label="Clear"
matSuffix mat-icon-button aria-label="Clear"
(click)="clearTargetDashboardState()">
<mat-icon class="material-icons">close</mat-icon>
</button>
@ -145,15 +145,13 @@
</section>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || widgetActionFormGroup.invalid || actionTypeFormGroup.invalid || (!widgetActionFormGroup.dirty && !actionTypeFormGroup.dirty)">
{{ (isAdd ? 'action.add' : 'action.save') | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

20
ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.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 ::ng-deep {
.mat-checkbox-label {
white-space: normal;
}
}

2
ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts

@ -55,7 +55,7 @@ export interface WidgetActionDialogData {
selector: 'tb-widget-action-dialog',
templateUrl: './widget-action-dialog.component.html',
providers: [{provide: ErrorStateMatcher, useExisting: WidgetActionDialogComponent}],
styleUrls: []
styleUrls: ['./widget-action-dialog.component.scss']
})
export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDialogComponent,
WidgetActionDescriptorInfo> implements OnInit, ErrorStateMatcher {

10
ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<form #dataKeyForm="ngForm" [formGroup]="dataKeyFormGroup" (ngSubmit)="save()" style="width: 600px;">
<mat-toolbar fxLayout="row" color="primary">
<form #dataKeyForm="ngForm" [formGroup]="dataKeyFormGroup" (ngSubmit)="save()" style="min-width: 480px;">
<mat-toolbar color="primary">
<h2>{{ 'datakey.configuration' | translate }}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -36,15 +36,13 @@
formControlName="dataKey">
</tb-data-key-config>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || dataKeyForm.invalid || !dataKeyForm.dirty">
{{ 'action.save' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

1
ui-ngx/src/app/modules/home/components/widget/data-key-config-dialog.component.scss

@ -17,5 +17,6 @@
.mat-dialog-content {
padding: 0 !important;
margin: 0 !important;
overflow: hidden;
}
}

21
ui-ngx/src/app/modules/home/components/widget/data-key-config.component.html

@ -15,10 +15,9 @@
limitations under the License.
-->
<mat-tab-group class="tb-datakey-config" [ngClass]="{'tb-headless': !displayAdvanced}"
class="tb-datakey-config">
<mat-tab-group class="tb-datakey-config" [ngClass]="{'tb-headless': !displayAdvanced}">
<mat-tab [formGroup]="dataKeyFormGroup" label="{{ 'datakey.settings' | translate }}">
<div class="mat-content mat-padding" fxLayout="column">
<div class="mat-padding settings" fxLayout="column">
<mat-form-field class="mat-block" *ngIf="modelValue.type !== dataKeyTypes.function">
<mat-label>{{ 'entity.key' | translate }}</mat-label>
<input matInput type="text" placeholder="{{ 'entity.key-name' | translate }}"
@ -28,7 +27,7 @@
[matAutocomplete]="keyAutocomplete">
<button *ngIf="dataKeyFormGroup.get('name').value"
type="button"
matSuffix mat-button mat-icon-button aria-label="Clear"
matSuffix mat-icon-button aria-label="Clear"
(click)="clearKey()">
<mat-icon class="material-icons">close</mat-icon>
</button>
@ -40,7 +39,7 @@
</mat-option>
</mat-autocomplete>
</mat-form-field>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start center" fxLayoutAlign.xs fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>datakey.label</mat-label>
<input matInput formControlName="label" required>
@ -53,7 +52,7 @@
formControlName="color">
</tb-color-input>
</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" *ngIf="modelValue.type !== dataKeyTypes.alarm">
<div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start center" fxLayoutAlign.xs fxLayoutGap="8px" *ngIf="modelValue.type !== dataKeyTypes.alarm">
<mat-form-field fxFlex>
<mat-label translate>datakey.units</mat-label>
<input matInput formControlName="units">
@ -94,12 +93,10 @@
</div>
</mat-tab>
<mat-tab [formGroup]="dataKeySettingsFormGroup" label="{{ 'datakey.advanced' | translate }}" *ngIf="displayAdvanced">
<div class="mat-content mat-padding" fxLayout="column">
<div style="overflow: auto;">
<tb-json-form
formControlName="settings">
</tb-json-form>
</div>
<div class="mat-padding" fxLayout="column">
<tb-json-form
formControlName="settings">
</tb-json-form>
</div>
</mat-tab>
</mat-tab-group>

22
ui-ngx/src/app/modules/home/components/widget/data-key-config.component.scss

@ -13,11 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import '../../../../../scss/constants';
:host {
.tb-datakey-config {
min-width: 500px !important;
min-height: 500px !important;
height: 500px !important;
height: 100%;
.settings{
&> :first-child{
padding-top: 12px;
}
&> :nth-child(n){
padding-right: 12px;
padding-left: 12px;
}
}
}
}
@ -25,7 +35,11 @@
.tb-datakey-config {
.mat-tab-body.mat-tab-body-active {
.mat-tab-body-content > div {
height: 100%;
height: calc(65vh - 50px);
overflow: initial;
@media #{$mat-xs} {
height: 500px;
}
}
}
}

5
ui-ngx/src/app/modules/home/components/widget/data-keys.component.scss

@ -15,6 +15,8 @@
*/
:host {
.mat-chip.mat-standard-chip {
overflow: hidden;
.tb-attribute-chip {
max-width: 100%;
color: rgb(66, 66, 66);
@ -32,7 +34,8 @@
.tb-chip-labels {
display: flex;
flex-direction: row;
min-width: 0px;
align-items: flex-end;
min-width: 0;
.tb-chip-label {
overflow: hidden;
text-overflow: ellipsis;

14
ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts

@ -16,23 +16,21 @@
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import {
Inject,
ComponentRef,
ElementRef,
ViewContainerRef,
Component,
ComponentFactory,
ComponentRef,
Inject,
Injector,
ReflectiveInjector,
Component,
OnDestroy
OnDestroy,
ViewContainerRef
} from '@angular/core';
import { DialogComponent } from '@shared/components/dialog.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router';
import {
CustomDialogComponent,
CUSTOM_DIALOG_DATA,
CustomDialogComponent,
CustomDialogData
} from '@home/components/widget/dialog/custom-dialog.component';

3
ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts

@ -14,9 +14,8 @@
/// limitations under the License.
///
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MatDialogRef } from '@angular/material/dialog';
import { Inject, InjectionToken } from '@angular/core';
import { DialogComponent } from '@shared/components/dialog.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router';

1
ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts

@ -21,7 +21,6 @@ import { AppState } from '@core/core.state';
import { IDynamicWidgetComponent, WidgetContext } from '@home/models/widget-component.models';
import { HttpErrorResponse } from '@angular/common/http';
import { RafService } from '@core/services/raf.service';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import {
NotificationHorizontalPosition,
NotificationType,

4
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html

@ -61,7 +61,7 @@
</div>
</mat-toolbar>
<div fxFlex class="table-container">
<mat-table [dataSource]="alarmsDatasource"
<table mat-table [dataSource]="alarmsDatasource"
matSort [matSortActive]="sortOrderProperty" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
<ng-container matColumnDef="select" sticky>
<mat-header-cell *matHeaderCellDef style="width: 30px;">
@ -124,7 +124,7 @@
'tb-current-entity': alarmsDatasource.isCurrentAlarm(alarm)}"
*matRowDef="let alarm; columns: displayedColumns;"
(click)="onRowClick($event, alarm)"></mat-row>
</mat-table>
</table>
<span [fxShow]="alarmsDatasource.isEmpty() | async"
fxLayoutAlign="center center"
class="no-data-found" translate>alarm.no-alarms-prompt</span>

4
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html

@ -38,7 +38,7 @@
</div>
</mat-toolbar>
<div fxFlex class="table-container">
<mat-table [dataSource]="entityDatasource"
<table mat-table [dataSource]="entityDatasource"
matSort [matSortActive]="sortOrderProperty" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
<ng-container [matColumnDef]="column.def" *ngFor="let column of columns; trackBy: trackByColumnDef;">
<mat-header-cell [ngStyle]="headerStyle(column)" *matHeaderCellDef mat-sort-header> {{ column.title }} </mat-header-cell>
@ -85,7 +85,7 @@
<mat-row [ngClass]="{'tb-current-entity': entityDatasource.isCurrentEntity(entity)}"
*matRowDef="let entity; columns: displayedColumns;"
(click)="onRowClick($event, entity)" (dblclick)="onRowClick($event, entity, true)"></mat-row>
</mat-table>
</table>
<span [fxShow]="entityDatasource.isEmpty() | async"
fxLayoutAlign="center center"
class="no-data-found" translate>entity.no-entities-prompt</span>

4
ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html

@ -41,7 +41,7 @@
[(selectedIndex)]="sourceIndex" (selectedIndexChange)="onSourceIndexChanged()">
<mat-tab *ngFor="let source of sources" label="{{ source.datasource.name }}">
<div fxFlex class="table-container">
<mat-table [dataSource]="source.timeseriesDatasource" [trackBy]="trackByRowIndex"
<table mat-table [dataSource]="source.timeseriesDatasource" [trackBy]="trackByRowIndex"
matSort [matSortActive]="source.pageLink.sortOrder.property" [matSortDirection]="source.pageLink.sortDirection()" matSortDisableClear>
<ng-container *ngIf="showTimestamp" [matColumnDef]="'0'">
<mat-header-cell *matHeaderCellDef mat-sort-header>Timestamp</mat-header-cell>
@ -94,7 +94,7 @@
<mat-header-row *matHeaderRowDef="source.displayedColumns; sticky: true"></mat-header-row>
<mat-row *matRowDef="let row; columns: source.displayedColumns;"
(click)="onRowClick($event, row)"></mat-row>
</mat-table>
</table>
<span [fxShow]="source.timeseriesDatasource.isEmpty() | async"
fxLayoutAlign="center center"
class="no-data-found" translate>widget.no-data-found</span>

162
ui-ngx/src/app/modules/home/components/widget/widget-config.component.html

@ -16,12 +16,12 @@
-->
<mat-tab-group [ngClass]="{'tb-headless': (widgetType === widgetTypes.static && !displayAdvanced())}"
fxFlex class="tb-widget-config tb-absolute-fill" [(selectedIndex)]="selectedTab">
class="tb-widget-config tb-absolute-fill" [(selectedIndex)]="selectedTab">
<mat-tab label="{{ 'widget-config.data' | translate }}" [fxShow]="widgetType !== widgetTypes.static">
<div [formGroup]="dataSettings" class="mat-content mat-padding" fxLayout="column" fxLayoutGap="8px">
<div *ngIf="widgetType === widgetTypes.timeseries || widgetType === widgetTypes.alarm"
fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center">
<div fxLayout="column" fxLayoutGap="8px" fxFlex>
<div *ngIf="widgetType === widgetTypes.timeseries || widgetType === widgetTypes.alarm" fxFlex="100"
fxLayout.xs="column" fxLayoutGap="8px" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutGap="8px" fxFlex.gt-xs>
<mat-checkbox formControlName="useDashboardTimewindow">
{{ 'widget-config.use-dashboard-timewindow' | translate }}
</mat-checkbox>
@ -29,8 +29,10 @@
{{ 'widget-config.display-timewindow' | translate }}
</mat-checkbox>
</div>
<section fxFlex fxLayout="row" fxLayoutAlign="start center" style="margin-bottom: 16px;">
<span [ngClass]="{'tb-disabled-label': dataSettings.get('useDashboardTimewindow').value}" translate style="padding-right: 8px;">widget-config.timewindow</span>
<section fxLayout="row" fxLayoutAlign="start center" fxLayout.lt-lg="column" fxLayoutAlign.lt-lg="center start"
fxFlex.gt-xs style="margin-bottom: 16px;">
<span [ngClass]="{'tb-disabled-label': dataSettings.get('useDashboardTimewindow').value}" translate
style="padding-right: 8px;">widget-config.timewindow</span>
<tb-timewindow asButton="true"
isEdit="true"
aggregation="{{ widgetType === widgetTypes.timeseries }}"
@ -38,10 +40,11 @@
</section>
</div>
<div *ngIf="widgetType === widgetTypes.alarm" fxLayout="column" fxLayoutAlign="center">
<div fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center" fxLayoutGap="8px">
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center"
fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>alarm.alarm-status</mat-label>
<mat-select matInput formControlName="alarmSearchStatus">
<mat-select formControlName="alarmSearchStatus">
<mat-option *ngFor="let searchStatus of alarmSearchStatuses" [value]="searchStatus">
{{ ('alarm.search-status.' + searchStatus) | translate }}
</mat-option>
@ -61,7 +64,8 @@
</mat-error>
</mat-form-field>
</div>
<div fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center" fxLayoutGap="8px">
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center"
fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>alarm.max-count-load</mat-label>
<input matInput required
@ -100,7 +104,7 @@
<mat-panel-title fxLayout="column">
<div class="tb-panel-title" translate>widget-config.datasources</div>
<div *ngIf="modelValue?.typeParameters && modelValue?.typeParameters.maxDatasources > -1"
class="tb-hint">{{ 'widget-config.maximum-datasources' | translate:{count: modelValue?.typeParameters.maxDatasources} }}</div>
class="tb-panel-hint">{{ 'widget-config.maximum-datasources' | translate:{count: modelValue?.typeParameters.maxDatasources} }}</div>
</mat-panel-title>
</mat-expansion-panel-header>
<div *ngIf="datasourcesFormArray().length === 0; else datasourcesTemplate">
@ -133,7 +137,7 @@
fxLayout.gt-sm="row"
fxLayoutAlign.gt-sm="start center">
<mat-form-field class="tb-datasource-type">
<mat-select matInput formControlName="type">
<mat-select formControlName="type">
<mat-option *ngFor="let datasourceType of datasourceTypes" [value]="datasourceType">
{{ datasourceTypesTranslations.get(datasourceType) | translate }}
</mat-option>
@ -172,7 +176,7 @@
</section>
<button [disabled]="isLoading$ | async"
type="button"
mat-button mat-icon-button color="primary"
mat-icon-button color="primary"
style="min-width: 40px;"
(click)="removeDatasource($index)"
matTooltip="{{ 'widget-config.remove-datasource' | translate }}"
@ -186,7 +190,7 @@
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<button [disabled]="isLoading$ | async"
type="button"
mat-button mat-raised-button color="primary"
mat-raised-button color="primary"
[fxShow]="modelValue?.typeParameters &&
(modelValue?.typeParameters.maxDatasources == -1 || datasourcesFormArray().controls.length < modelValue?.typeParameters.maxDatasources)"
(click)="addDatasource()"
@ -228,7 +232,7 @@
fxLayout.gt-sm="row"
fxLayoutAlign.gt-sm="start center">
<mat-form-field class="tb-datasource-type">
<mat-select matInput formControlName="type">
<mat-select formControlName="type">
<mat-option *ngFor="let datasourceType of datasourceTypes" [value]="datasourceType">
{{ datasourceTypesTranslations.get(datasourceType) | translate }}
</mat-option>
@ -268,15 +272,20 @@
</div>
</mat-tab>
<mat-tab label="{{ 'widget-config.settings' | translate }}">
<div class="mat-content mat-padding"
fxLayout="column" fxLayoutGap="8px">
<div class="mat-content mat-padding" fxLayout="column" fxLayoutGap="8px">
<div [formGroup]="widgetSettings" fxLayout="column" fxLayoutGap="8px">
<span translate>widget-config.general-settings</span>
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widget-config.title</mat-label>
<input matInput formControlName="title">
</mat-form-field>
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center" fxFlex.sm="40%" fxFlex.gt-sm="30%">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widget-config.title</mat-label>
<input matInput formControlName="title">
</mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>widget-config.title-tooltip</mat-label>
<input matInput formControlName="titleTooltip">
</mat-form-field>
</div>
<div fxFlex [fxShow]="widgetSettings.get('showTitle').value">
<tb-json-object-edit
[editorStyle]="{minHeight: '100px'}"
@ -286,46 +295,40 @@
></tb-json-object-edit>
</div>
</div>
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-md="row" fxLayoutAlign.gt-md="start center" fxFlex="100%"
fxLayoutGap="8px">
<div fxLayout="row" fxFlex>
<mat-checkbox formControlName="showTitleIcon">
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px" fxFlex.gt-md>
<mat-checkbox fxFlex formControlName="showTitleIcon">
{{ 'widget-config.display-icon' | translate }}
</mat-checkbox>
</div>
<div fxFlex>
<tb-material-icon-select
<tb-material-icon-select fxFlex
formControlName="titleIcon">
</tb-material-icon-select>
</div>
<tb-color-input fxFlex
label="{{'widget-config.icon-color' | translate}}"
icon="format_color_fill"
openOnInput
formControlName="iconColor">
</tb-color-input>
<mat-form-field fxFlex>
<mat-label translate>widget-config.icon-size</mat-label>
<input matInput formControlName="iconSize">
</mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>widget-config.title-tooltip</mat-label>
<input matInput formControlName="titleTooltip">
</mat-form-field>
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px" fxFlex.gt-md>
<tb-color-input fxFlex
label="{{'widget-config.icon-color' | translate}}"
icon="format_color_fill"
openOnInput
formControlName="iconColor">
</tb-color-input>
<mat-form-field fxFlex>
<mat-label translate>widget-config.icon-size</mat-label>
<input matInput formControlName="iconSize">
</mat-form-field>
</div>
</div>
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px">
<div fxLayout="row">
<div fxLayout="column" fxLayoutAlign="center" fxLayoutGap="8px" fxFlex.sm="40%" fxFlex.gt-sm="30%">
<mat-checkbox formControlName="showTitle">
{{ 'widget-config.display-title' | translate }}
</mat-checkbox>
</div>
<div fxLayout="row">
<mat-checkbox formControlName="dropShadow">
{{ 'widget-config.drop-shadow' | translate }}
</mat-checkbox>
</div>
<div fxLayout="row">
<mat-checkbox formControlName="enableFullscreen">
{{ 'widget-config.enable-fullscreen' | translate }}
</mat-checkbox>
@ -339,30 +342,36 @@
></tb-json-object-edit>
</div>
</div>
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
fxLayoutGap="8px">
<tb-color-input fxFlex
label="{{'widget-config.background-color' | translate}}"
icon="format_color_fill"
openOnInput
formControlName="backgroundColor">
</tb-color-input>
<tb-color-input fxFlex
label="{{'widget-config.text-color' | translate}}"
icon="format_color_fill"
openOnInput
formControlName="color">
</tb-color-input>
<mat-form-field fxFlex>
<mat-label translate>widget-config.padding</mat-label>
<input matInput formControlName="padding">
</mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>widget-config.margin</mat-label>
<input matInput formControlName="margin">
</mat-form-field>
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-md="row" fxLayoutAlign.gt-md="start center"
fxFlex="100%" fxLayoutGap="8px">
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px" fxFlex.gt-md>
<tb-color-input fxFlex
label="{{'widget-config.background-color' | translate}}"
icon="format_color_fill"
openOnInput
formControlName="backgroundColor">
</tb-color-input>
<tb-color-input fxFlex
label="{{'widget-config.text-color' | translate}}"
icon="format_color_fill"
openOnInput
formControlName="color">
</tb-color-input>
</div>
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px" fxFlex.gt-md>
<mat-form-field fxFlex>
<mat-label translate>widget-config.padding</mat-label>
<input matInput formControlName="padding">
</mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>widget-config.margin</mat-label>
<input matInput formControlName="margin">
</mat-form-field>
</div>
</div>
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px">
<mat-form-field fxFlex>
<mat-label translate>widget-config.units</mat-label>
@ -373,14 +382,13 @@
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1">
</mat-form-field>
</div>
<div [fxShow]="widgetType === widgetTypes.timeseries ||
widgetType === widgetTypes.latest"
fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
fxLayoutGap="8px">
<mat-checkbox fxFlex formControlName="showLegend">
<div [fxShow]="widgetType === widgetTypes.timeseries || widgetType === widgetTypes.latest"
fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px" fxFlex="100%">
<mat-checkbox fxFlex.gt-xs formControlName="showLegend">
{{ 'widget-config.display-legend' | translate }}
</mat-checkbox>
<section fxFlex fxLayout="row" fxLayoutAlign="start center" style="margin-bottom: 16px;">
<section fxFlex.gt-xs fxLayout="row" fxLayoutAlign="start center" style="margin-bottom: 16px;">
<tb-legend-config formControlName="legendConfig">
</tb-legend-config>
</section>
@ -388,7 +396,7 @@
</div>
<div [formGroup]="layoutSettings" fxLayout="column" fxLayoutGap="8px">
<span translate>widget-config.mobile-mode-settings</span>
<div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px">
<mat-form-field fxFlex>
<mat-label translate>widget-config.order</mat-label>

24
ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss

@ -57,14 +57,26 @@
right: 0;
bottom: 0;
}
.mat-tab-body.mat-tab-body-active {
.mat-tab-body-content > div {
height: 100%;
}
.tb-panel-hint {
font-size: 12px;
color: #808080;
}
//.mat-tab-body.mat-tab-body-active {
// .mat-tab-body-content > div {
// height: 100%;
// }
//}
.mat-checkbox-label {
white-space: normal;
}
.mat-expansion-panel {
&.tb-datasources.mat-expanded {
overflow: visible;
&.tb-datasources{
&.mat-expanded {
overflow: visible;
}
.mat-expansion-panel-body{
padding: 0 12px 16px;
}
}
.mat-expansion-panel-content {
font: inherit;

2
ui-ngx/src/app/modules/home/home.component.ts

@ -50,7 +50,7 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni
sidenavMode: 'over' | 'push' | 'side' = 'side';
sidenavOpened = true;
logo = require('../../../assets/logo_title_white.svg');
logo = require('../../../assets/logo_title_white.svg').default;
@ViewChild('sidenav')
sidenav: MatSidenav;

13
ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.html

@ -16,11 +16,11 @@
-->
<form #widgetForm="ngForm" [formGroup]="widgetFormGroup" (ngSubmit)="add()" style="width: 900px;">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2 translate>widget.add</h2>
<span fxFlex></span>
<div [tb-help]="helpLinkIdForWidgetType()"></div>
<button mat-button mat-icon-button
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
@ -39,18 +39,17 @@
</tb-widget-config>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || widgetFormGroup.invalid">
{{ 'action.add' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
(click)="cancel()"
cdkFocusInitial>
{{ 'action.cancel' | translate }}
</button>
</div>

8
ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.ts

@ -23,9 +23,6 @@ import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm } from
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { Widget, widgetTypesData } from '@shared/models/widget.models';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { EntityService } from '@core/http/entity.service';
import { Dashboard } from '@app/shared/models/dashboard.models';
import { IAliasController } from '@core/api/widget-api.models';
import { WidgetConfigComponentData, WidgetInfo } from '@home/models/widget-component.models';
@ -60,10 +57,7 @@ export class AddWidgetDialogComponent extends DialogComponent<AddWidgetDialogCom
@Inject(MAT_DIALOG_DATA) public data: AddWidgetDialogData,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
public dialogRef: MatDialogRef<AddWidgetDialogComponent, Widget>,
private fb: FormBuilder,
private utils: UtilsService,
private translate: TranslateService,
private entityService: EntityService) {
private fb: FormBuilder) {
super(store, router, dialogRef);
this.dashboard = this.data.dashboard;

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

@ -69,7 +69,7 @@
</mat-form-field>
<div fxLayout="column" [fxShow]="!isEdit && (dashboardScope === 'tenant' && isPublic(entity)
|| dashboardScope === 'customer' && isCurrentPublicCustomer(entity))">
<tb-social-share-panel style="padding-bottom: 10px;"
<tb-social-share-panel style="padding-bottom: 1.25em;"
shareTitle="{{ 'dashboard.socialshare-title' | translate:{dashboardTitle: entity?.title} }}"
shareText="{{ 'dashboard.socialshare-text' | translate:{dashboardTitle: entity?.title} }}"
shareLink="{{ publicLink }}"

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

@ -27,27 +27,27 @@
fxLayoutAlign="center stretch" fxLayoutAlign.gt-sm="space-between center">
<div class="tb-dashboard-action-panel" fxFlex.md="30" fxLayout="row-reverse"
fxLayoutAlign.gt-sm="start center" fxLayoutAlign="space-between center" fxLayoutGap="12px">
<button [fxShow]="showCloseToolbar()" mat-button mat-icon-button class="close-action"
<button [fxShow]="showCloseToolbar()" mat-icon-button class="close-action"
matTooltip="{{ 'dashboard.close-toolbar' | translate }}"
matTooltipPosition="below"
(click)="closeToolbar()">
<mat-icon>arrow_forward</mat-icon>
</button>
<tb-user-menu *ngIf="!isPublicUser() && forceFullscreen" fxHide.xs fxHide.sm displayUserInfo="true">
<tb-user-menu *ngIf="!isPublicUser() && forceFullscreen" fxHide.lt-md displayUserInfo="true">
</tb-user-menu>
<button [fxShow]="showRightLayoutSwitch()" mat-button mat-icon-button
<button [fxShow]="showRightLayoutSwitch()" mat-icon-button
matTooltip="{{ (isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }}"
matTooltipPosition="below"
(click)="toggleLayouts()">
<mat-icon>{{isRightLayoutOpened ? 'arrow_back' : 'menu'}}</mat-icon>
</button>
<button [fxShow]="!hideFullscreenButton()" mat-button mat-icon-button
<button [fxShow]="!hideFullscreenButton()" mat-icon-button
matTooltip="{{(isFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
matTooltipPosition="below"
(click)="isFullscreen = !isFullscreen">
<mat-icon>{{ isFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
</button>
<button [fxShow]="isEdit || displayExport()" mat-button mat-icon-button
<button [fxShow]="isEdit || displayExport()" mat-icon-button
matTooltip="{{'dashboard.export' | translate}}"
matTooltipPosition="below"
(click)="exportDashboard($event)">
@ -65,13 +65,13 @@
tooltipPosition="below"
[aliasController]="dashboardCtx.aliasController">
</tb-aliases-entity-select>
<button [fxShow]="isEdit" mat-button mat-icon-button
<button [fxShow]="isEdit" mat-icon-button
matTooltip="{{ 'entity.aliases' | translate }}"
matTooltipPosition="below"
(click)="openEntityAliases($event)">
<mat-icon>devices_other</mat-icon>
</button>
<button [fxShow]="isEdit" mat-button mat-icon-button
<button [fxShow]="isEdit" mat-icon-button
matTooltip="{{ 'dashboard.settings' | translate }}"
matTooltipPosition="below"
(click)="openDashboardSettings($event)">
@ -89,23 +89,23 @@
<tb-user-menu *ngIf="!isPublicUser() && forceFullscreen" fxHide.gt-sm displayUserInfo="true">
</tb-user-menu>
<div [fxShow]="isEdit"
fxFlex.xs fxFlex.sm fxLayout="row"
fxFlex.lt-md fxLayout="row"
fxLayoutAlign.gt-sm="start center"
fxLayoutAlign="space-between center" fxLayoutGap="12px">
<button mat-button mat-icon-button
fxLayoutAlign="end center" fxLayoutGap="12px">
<button mat-icon-button
matTooltip="{{'dashboard.manage-states' | translate}}"
matTooltipPosition="below"
(click)="manageDashboardStates($event)">
<mat-icon>layers</mat-icon>
</button>
<button mat-button mat-icon-button
<button mat-icon-button
matTooltip="{{'layout.manage' | translate}}"
matTooltipPosition="below"
(click)="manageDashboardLayouts($event)">
<mat-icon>view_compact</mat-icon>
</button>
</div>
<tb-states-component fxFlex.xs fxFlex.sm
<tb-states-component fxFlex.lt-md
[statesControllerId]="isEdit ? 'default' : dashboardConfiguration.settings.stateControllerId"
[dashboardCtrl]="this"
[dashboardId]="dashboard.id ? dashboard.id.id : ''"

20
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-settings-dialog.component.html

@ -16,7 +16,7 @@
-->
<form #settingsForm="ngForm" (ngSubmit)="save()">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2 translate>{{settings ? 'dashboard.settings' : 'layout.settings'}}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -28,17 +28,17 @@
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div mat-dialog-content>
<fieldset [disabled]="isLoading$ | async">
<fieldset [disabled]="isLoading$ | async" fxLayout="column" fxLayoutGap="16px">
<div *ngIf="settings" [formGroup]="settingsFormGroup">
<mat-form-field class="mat-block">
<mat-label translate>dashboard.state-controller</mat-label>
<mat-select required matInput formControlName="stateControllerId">
<mat-select required formControlName="stateControllerId">
<mat-option *ngFor="let stateControllerId of stateControllerIds" [value]="stateControllerId">
{{stateControllerId}}
</mat-option>
</mat-select>
</mat-form-field>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.lt-md="column" fxLayoutAlign.lt-md fxLayoutGap="8px">
<mat-checkbox fxFlex formControlName="toolbarAlwaysOpen">
{{ 'dashboard.toolbar-always-open' | translate }}
</mat-checkbox>
@ -52,7 +52,7 @@
formControlName="titleColor">
</tb-color-input>
</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.lt-md="column" fxLayoutAlign.lt-md fxLayoutGap="8px">
<mat-checkbox fxFlex formControlName="showDashboardsSelect">
{{ 'dashboard.display-dashboards-selection' | translate }}
</mat-checkbox>
@ -117,7 +117,7 @@
</tb-image-input>
<mat-form-field class="mat-block">
<mat-label translate>dashboard.background-size-mode</mat-label>
<mat-select matInput formControlName="backgroundSizeMode">
<mat-select formControlName="backgroundSizeMode">
<mat-option value="100%">Fit width</mat-option>
<mat-option value="auto 100%">Fit height</mat-option>
<mat-option value="cover">Cover</mat-option>
@ -126,7 +126,7 @@
</mat-select>
</mat-form-field>
<small translate>dashboard.mobile-layout</small>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.xs="column" fxLayoutAlign.xs fxLayoutGap="8px" style="margin-top: 8px">
<mat-checkbox fxFlex formControlName="mobileAutoFillHeight">
{{ 'dashboard.autofill-height' | translate }}
</mat-checkbox>
@ -148,16 +148,14 @@
</div>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || settingsFormGroup.invalid || gridSettingsFormGroup.invalid
|| (!settingsFormGroup.dirty && !gridSettingsFormGroup.dirty)">
{{ 'action.save' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

14
common/dao-api/src/main/java/org/thingsboard/server/dao/util/NoSqlDao.java → ui-ngx/src/app/modules/home/pages/dashboard/dashboard-settings-dialog.component.scss

@ -13,10 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.util;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
:host {
small {
white-space: normal;
}
}
@ConditionalOnProperty(prefix = "database.entities", value = "type", havingValue = "cassandra")
public @interface NoSqlDao {
:host ::ng-deep {
.mat-checkbox-label {
white-space: normal;
}
}

2
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-settings-dialog.component.ts

@ -38,7 +38,7 @@ export interface DashboardSettingsDialogData {
selector: 'tb-dashboard-settings-dialog',
templateUrl: './dashboard-settings-dialog.component.html',
providers: [{provide: ErrorStateMatcher, useExisting: DashboardSettingsDialogComponent}],
styleUrls: []
styleUrls: ['./dashboard-settings-dialog.component.scss']
})
export class DashboardSettingsDialogComponent extends DialogComponent<DashboardSettingsDialogComponent, DashboardSettingsDialogData>
implements OnInit, ErrorStateMatcher {

6
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-toolbar.component.html

@ -15,12 +15,10 @@
limitations under the License.
-->
<mat-fab-toolbar [isOpen]="toolbarOpened"
color="primary"
direction="left"
<mat-fab-toolbar [isOpen]="toolbarOpened" color="primary" direction="left"
[ngClass]="{'is-fullscreen': forceFullscreen, 'mat-elevation-z1': forceFullscreen && toolbarOpened }">
<mat-fab-trigger>
<button mat-button mat-icon-button mat-fab color="primary"
<button mat-fab color="primary"
[matTooltip]="!toolbarOpened ? ('dashboard.open-toolbar' | translate) : ''"
matTooltipPosition="below"
(click)="onTriggerClick()">

29
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-toolbar.component.scss

@ -24,29 +24,12 @@ $mobile-toolbar-height-total: 84px !default;
tb-dashboard-toolbar {
mat-fab-toolbar {
mat-fab-trigger {
.mat-button {
&.mat-fab {
width: 36px;
height: 36px;
margin: 4px 0 0 4px;
line-height: 36px;
.mat-button-wrapper {
width: 36px;
height: 36px;
padding: 0 6px;
box-sizing: border-box;
}
mat-icon {
display: block;
position: absolute;
top: 25%;
width: 18px;
min-width: 18px;
height: 18px;
min-height: 18px;
margin: 0;
line-height: 18px;
}
.mat-fab {
width: 36px;
height: 36px;
margin: 4px 0 0 4px;
.mat-button-wrapper {
padding: 0;
}
}
}

2
ui-ngx/src/app/modules/home/pages/dashboard/layout/dashboard-layout.component.ts

@ -28,7 +28,7 @@ import {
WidgetContextMenuItem
} from '@home/models/dashboard-component.models';
import { Subscription } from 'rxjs';
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
import { Hotkey } from 'angular2-hotkeys';
import { TranslateService } from '@ngx-translate/core';
import { ItemBufferService } from '@app/core/services/item-buffer.service';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';

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

@ -14,9 +14,6 @@
/// limitations under the License.
///
import { Widget } from '@shared/models/widget.models';
import { WidgetLayout } from '@shared/models/dashboard.models';
export interface ILayoutController {
reload();
resetHighlight();

27
ui-ngx/src/app/modules/home/pages/dashboard/layout/manage-dashboard-layouts-dialog.component.html

@ -16,7 +16,7 @@
-->
<form #widgetForm="ngForm" [formGroup]="layoutsFormGroup" (ngSubmit)="save()">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar color="primary">
<h2 translate>layout.manage</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -38,33 +38,32 @@
</mat-checkbox>
</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<button fxFlex fxLayout="column"
type="button" mat-button mat-raised-button color="primary"
<button fxFlex
type="button" mat-raised-button color="primary"
class="tb-layout-button"
(click)="openLayoutSettings('main')">
<span translate>layout.main</span>
</button>
<button fxFlex fxLayout="column" [fxShow]="layoutsFormGroup.get('right').value"
type="button" mat-button mat-raised-button color="primary"
<button fxFlex [fxShow]="layoutsFormGroup.get('right').value"
type="button" mat-raised-button color="primary"
class="tb-layout-button"
(click)="openLayoutSettings('right')">
(click)="openLayoutSettings('right')">
<span translate>layout.right</span>
</button>
</div>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || layoutsFormGroup.invalid || !layoutsFormGroup.dirty">
[disabled]="(isLoading$ | async) || layoutsFormGroup.invalid || !layoutsFormGroup.dirty">
{{ 'action.save' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
<button mat-button
color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
{{ 'action.cancel' | translate }}
</button>
</div>

11
ui-ngx/src/app/modules/home/pages/dashboard/layout/manage-dashboard-layouts-dialog.component.ts

@ -16,22 +16,17 @@
import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms';
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { Widget, widgetTypesData } from '@shared/models/widget.models';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { EntityService } from '@core/http/entity.service';
import { Dashboard, DashboardLayoutId, DashboardStateLayouts } from '@app/shared/models/dashboard.models';
import { IAliasController } from '@core/api/widget-api.models';
import { WidgetConfigComponentData, WidgetInfo } from '@home/models/widget-component.models';
import { deepClone, isDefined, isString } from '@core/utils';
import { DashboardLayoutId, DashboardStateLayouts } from '@app/shared/models/dashboard.models';
import { deepClone, isDefined } from '@core/utils';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import { MatDialog } from '@angular/material/dialog';
import {
DashboardSettingsDialogComponent,
DashboardSettingsDialogData

10
ui-ngx/src/app/modules/home/pages/dashboard/states/dashboard-state-dialog.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<form #stateForm="ngForm" [formGroup]="stateFormGroup" (ngSubmit)="save()" style="min-width: 600px;">
<mat-toolbar fxLayout="row" color="primary">
<form #stateForm="ngForm" [formGroup]="stateFormGroup" (ngSubmit)="save()" style="min-width: 480px;">
<mat-toolbar color="primary">
<h2 translate>{{ isAdd ? 'dashboard.add-state' : 'dashboard.edit-state' }}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -51,15 +51,13 @@
</mat-checkbox>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || stateFormGroup.invalid || !stateFormGroup.dirty">
{{ (isAdd ? 'action.add' : 'action.save') | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

4
ui-ngx/src/app/modules/home/pages/dashboard/states/dashboard-state-dialog.component.ts

@ -31,7 +31,6 @@ import {
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { DashboardState } from '@app/shared/models/dashboard.models';
import { MatDialog } from '@angular/material/dialog';
import { DashboardStateInfo } from '@home/pages/dashboard/states/manage-dashboard-states-dialog.component.models';
import { TranslateService } from '@ngx-translate/core';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
@ -71,8 +70,7 @@ export class DashboardStateDialogComponent extends
public dialogRef: MatDialogRef<DashboardStateDialogComponent, DashboardStateInfo>,
private fb: FormBuilder,
private translate: TranslateService,
private dashboardUtils: DashboardUtilsService,
private dialog: MatDialog) {
private dashboardUtils: DashboardUtilsService) {
super(store, router, dialogRef);
this.states = this.data.states;

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

@ -201,7 +201,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
const entityName = targetParams && targetParams.entityName ? targetParams.entityName : '';
const entityLabel = targetParams && targetParams.entityLabel ? targetParams.entityLabel : '';
result = this.utils.insertVariable(stateName, 'entityName', entityName);
result = this.utils.insertVariable(stateName, 'entityLabel', entityLabel);
result = this.utils.insertVariable(result, 'entityLabel', entityLabel);
for (const prop of Object.keys(params)) {
if (params[prop] && params[prop].entityName) {
result = this.utils.insertVariable(result, prop + ':entityName', params[prop].entityName);

30
ui-ngx/src/app/modules/home/pages/dashboard/states/manage-dashboard-states-dialog.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<form #statesForm="ngForm" [formGroup]="statesFormGroup" (ngSubmit)="save()" style="min-width: 620px;">
<mat-toolbar fxLayout="row" color="primary">
<form #statesForm="ngForm" [formGroup]="statesFormGroup" (ngSubmit)="save()" style="min-width: 480px;">
<mat-toolbar color="primary">
<h2 translate>dashboard.manage-states</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
@ -36,14 +36,14 @@
<div class="mat-toolbar-tools">
<span class="tb-entity-table-title" translate>dashboard.states</span>
<span fxFlex></span>
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
<button mat-icon-button [disabled]="isLoading$ | async"
type="button"
(click)="addState($event)"
matTooltip="{{ 'dashboard.add-state' | translate }}"
matTooltipPosition="above">
<mat-icon>add</mat-icon>
</button>
<button mat-button mat-icon-button [disabled]="isLoading$ | async" (click)="enterFilterMode()"
<button mat-icon-button [disabled]="isLoading$ | async" (click)="enterFilterMode()"
type="button"
matTooltip="{{ 'action.search' | translate }}"
matTooltipPosition="above">
@ -53,7 +53,7 @@
</mat-toolbar>
<mat-toolbar class="mat-table-toolbar" [fxShow]="textSearchMode">
<div class="mat-toolbar-tools">
<button mat-button mat-icon-button
<button mat-icon-button
type="button"
matTooltip="{{ 'dashboard.search-states' | translate }}"
matTooltipPosition="above">
@ -66,7 +66,7 @@
[ngModelOptions]="{standalone: true}"
placeholder="{{ 'dashboard.search-states' | translate }}"/>
</mat-form-field>
<button mat-button mat-icon-button (click)="exitFilterMode()"
<button mat-icon-button (click)="exitFilterMode()"
type="button"
matTooltip="{{ 'action.close' | translate }}"
matTooltipPosition="above">
@ -75,16 +75,16 @@
</div>
</mat-toolbar>
<div class="table-container">
<mat-table [dataSource]="dataSource"
<table mat-table [dataSource]="dataSource"
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 60%"> {{ 'dashboard.state-name' | translate }} </mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header style="flex: 0 0 60%"> {{ 'dashboard.state-name' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let state">
{{ state.name }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 40%"> {{ 'dashboard.state-id' | translate }} </mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header style="flex: 0 0 40%"> {{ 'dashboard.state-id' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let state">
{{ state.id }}
</mat-cell>
@ -100,14 +100,14 @@
</mat-header-cell>
<mat-cell *matCellDef="let state">
<div fxFlex fxLayout="row">
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
<button mat-icon-button [disabled]="isLoading$ | async"
type="button"
matTooltip="{{ 'dashboard.edit-state' | translate }}"
matTooltipPosition="above"
(click)="editState($event, state)">
<mat-icon>edit</mat-icon>
</button>
<button [fxShow]="!state.root" mat-button mat-icon-button [disabled]="isLoading$ | async"
<button [fxShow]="!state.root" mat-icon-button [disabled]="isLoading$ | async"
type="button"
matTooltip="{{ 'dashboard.delete-state' | translate }}"
matTooltipPosition="above"
@ -120,7 +120,7 @@
<mat-header-row class="mat-row-select" *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row class="mat-row-select"
*matRowDef="let state; columns: displayedColumns;"></mat-row>
</mat-table>
</table>
<span [fxShow]="dataSource.isEmpty() | async"
fxLayoutAlign="center center"
class="no-data-found" translate>{{ 'dashboard.no-states-text' }}</span>
@ -135,15 +135,13 @@
</div>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row">
<span fxFlex></span>
<button mat-button mat-raised-button color="primary"
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || statesFormGroup.invalid || !statesFormGroup.dirty">
{{ 'action.save' | translate }}
</button>
<button mat-button color="primary"
style="margin-right: 20px;"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>

8
ui-ngx/src/app/modules/home/pages/dashboard/states/states-component.directive.ts

@ -17,20 +17,16 @@
import {
ComponentRef,
Directive,
ElementRef,
Input,
OnChanges,
OnInit,
OnDestroy,
OnInit,
SimpleChanges,
ViewContainerRef,
ChangeDetectorRef
ViewContainerRef
} from '@angular/core';
import { DashboardPageComponent } from '@home/pages/dashboard/dashboard-page.component';
import { DashboardState } from '@shared/models/dashboard.models';
import { IDashboardController } from '@home/pages/dashboard/dashboard-page.models';
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
import { IStateController } from '@core/api/widget-api.models';
import { IStateControllerComponent } from '@home/pages/dashboard/states/state-controller.models';
@Directive({

32
ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html

@ -34,23 +34,23 @@
</mat-select>
</mat-form-field>
<span fxFlex></span>
<button mat-button fxHide.xs fxHide.sm [disabled]="!iframeWidgetEditModeInited"
<button mat-button fxHide.lt-md [disabled]="!iframeWidgetEditModeInited"
(click)="applyWidgetScript()"
matTooltip="{{ 'widget.run' | translate }} (CTRL + Return)"
matTooltipPosition="below">
<mat-icon>play_arrow</mat-icon>
<span translate>action.run</span>
</button>
<button mat-button mat-raised-button
fxHide.xs fxHide.sm [disabled]="(isLoading$ | async) || undoDisabled()"
<button mat-raised-button
fxHide.lt-md [disabled]="(isLoading$ | async) || undoDisabled()"
(click)="undoWidget()"
matTooltip="{{ 'widget.undo' | translate }} (CTRL + Q)"
matTooltipPosition="below">
<mat-icon>undo</mat-icon>
<span translate>action.undo</span>
</button>
<button *ngIf="!isReadOnly" mat-button mat-raised-button
fxHide.xs fxHide.sm [disabled]="(isLoading$ | async) || saveDisabled()"
<button *ngIf="!isReadOnly" mat-raised-button
fxHide.lt-md [disabled]="(isLoading$ | async) || saveDisabled()"
(click)="saveWidget()"
[tb-circular-progress]="saveWidgetPending"
matTooltip="{{ 'widget.save' | translate }} (CTRL + S)"
@ -58,8 +58,8 @@
<mat-icon>save</mat-icon>
<span translate>action.save</span>
</button>
<button mat-button mat-raised-button
fxHide.xs fxHide.sm [disabled]="(isLoading$ | async) || saveAsDisabled()"
<button mat-raised-button
fxHide.lt-md [disabled]="(isLoading$ | async) || saveAsDisabled()"
(click)="saveWidgetAs()"
[tb-circular-progress]="saveWidgetAsPending"
matTooltip="{{ 'widget.saveAs' | translate }} (Shift + CTRL + S)"
@ -68,14 +68,14 @@
<span translate>action.saveAs</span>
</button>
<button mat-button
fxHide.xs fxHide.sm
fxHide.lt-md
(click)="fullscreen = !fullscreen"
matTooltip="{{ 'widget.toggle-fullscreen' | translate }} (Shift + CTRL + F)"
matTooltipPosition="below">
<mat-icon>{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
<span translate>widget.toggle-fullscreen</span>
</button>
<button mat-button mat-icon-button fxHide.gt-sm
<button mat-icon-button fxHide.gt-sm
[matMenuTriggerFor]="widgetEditMenu">
<mat-icon>more_vert</mat-icon>
</button>
@ -123,7 +123,7 @@
(ngModelChange)="isDirty = true"
placeholder="{{ 'widget.resource-url' | translate }}"/>
</mat-form-field>
<button mat-button mat-icon-button color="primary"
<button mat-icon-button color="primary"
[disabled]="isLoading$ | async"
(click)="removeResource(i)"
matTooltip="{{'widget.remove-resource' | translate}}"
@ -132,7 +132,7 @@
</button>
</div>
<div style="margin-top: 6px;">
<button mat-button mat-raised-button color="primary"
<button mat-raised-button color="primary"
[disabled]="isLoading$ | async"
(click)="addResource()"
matTooltip="{{'widget.add-resource' | translate}}"
@ -165,7 +165,7 @@
<button mat-button (click)="beautifyCss()">
{{ 'widget.tidy' | translate }}
</button>
<button mat-button mat-icon-button class="tb-mat-32"
<button mat-icon-button class="tb-mat-32"
(click)="cssFullscreen = !cssFullscreen"
matTooltip="{{(cssFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
matTooltipPosition="above">
@ -185,7 +185,7 @@
<button mat-button (click)="beautifyJson()">
{{ 'widget.tidy' | translate }}
</button>
<button mat-button mat-icon-button class="tb-mat-32"
<button mat-icon-button class="tb-mat-32"
(click)="jsonSettingsFullscreen = !jsonSettingsFullscreen"
matTooltip="{{(jsonSettingsFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
matTooltipPosition="above">
@ -201,7 +201,7 @@
<button mat-button (click)="beautifyDataKeyJson()">
{{ 'widget.tidy' | translate }}
</button>
<button mat-button mat-icon-button class="tb-mat-32"
<button mat-icon-button class="tb-mat-32"
(click)="jsonDataKeySettingsFullscreen = !jsonDataKeySettingsFullscreen"
matTooltip="{{(jsonDataKeySettingsFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
matTooltipPosition="above">
@ -222,7 +222,7 @@
<button mat-button (click)="beautifyJs()">
{{ 'widget.tidy' | translate }}
</button>
<button mat-button mat-icon-button class="tb-mat-32"
<button mat-icon-button class="tb-mat-32"
(click)="javascriptFullscreen = !javascriptFullscreen"
matTooltip="{{(javascriptFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
matTooltipPosition="above">
@ -240,7 +240,7 @@
<div tb-fullscreen [fullscreen]="iFrameFullscreen" style="width: 100%; height: 100%;">
<iframe #widgetIFrame frameborder="0" height="100%" width="100%"></iframe>
<div style="position: absolute; top: 10px; left: 10px; bottom: initial;">
<button mat-button mat-icon-button
<button mat-icon-button
class="tb-fullscreen-button-style"
(click)="iFrameFullscreen = !iFrameFullscreen"
matTooltip="{{(iFrameFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"

7
ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts

@ -21,7 +21,7 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { WidgetService } from '@core/http/widget.service';
import { toWidgetInfo, WidgetInfo } from '@home/models/widget-component.models';
import { WidgetConfig, widgetType, WidgetType, widgetTypesData, Widget } from '@shared/models/widget.models';
import { Widget, WidgetConfig, WidgetType, widgetType, widgetTypesData } from '@shared/models/widget.models';
import { ActivatedRoute, Router } from '@angular/router';
import { deepClone } from '@core/utils';
import { HasDirtyFlag } from '@core/guards/confirm-on-exit.guard';
@ -29,7 +29,7 @@ import { AuthUser } from '@shared/models/user.model';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
import { Hotkey } from 'angular2-hotkeys';
import { TranslateService } from '@ngx-translate/core';
import { getCurrentIsLoading } from '@app/core/interceptors/load.selectors';
import * as ace from 'ace-builds';
@ -38,15 +38,14 @@ import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
import { WINDOW } from '@core/services/window.service';
import { WindowMessage } from '@shared/models/window-message.model';
import { ExceptionData } from '@shared/models/error.models';
import Timeout = NodeJS.Timeout;
import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions';
import { MatDialog } from '@angular/material/dialog';
import { SelectWidgetTypeDialogComponent } from '@home/pages/widget/select-widget-type-dialog.component';
import {
SaveWidgetTypeAsDialogComponent,
SaveWidgetTypeAsDialogResult
} from '@home/pages/widget/save-widget-type-as-dialog.component';
import { Subscription } from 'rxjs';
import Timeout = NodeJS.Timeout;
// @dynamic
@Component({

6
ui-ngx/src/app/shared/components/color-input.component.scss

@ -18,3 +18,9 @@
width: 100%;
}
}
:host ::ng-deep {
.mat-form-field-infix{
width: 150px;
}
}

22
ui-ngx/src/app/shared/components/color-input.component.ts

@ -14,30 +14,12 @@
/// limitations under the License.
///
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { DataKey, DatasourceType } from '@shared/models/widget.models';
import {
ControlValueAccessor,
FormBuilder,
FormControl,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
Validator,
Validators
} from '@angular/forms';
import { UtilsService } from '@core/services/utils.service';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { MatDialog } from '@angular/material/dialog';
import { EntityService } from '@core/http/entity.service';
import { DataKeysCallbacks } from '@home/components/widget/data-keys.component.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { Observable, of } from 'rxjs';
import { map, mergeMap, tap } from 'rxjs/operators';
import { alarmFields } from '@shared/models/alarm.models';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { DialogService } from '@core/services/dialog.service';

31
ui-ngx/src/app/shared/components/dashboard-autocomplete.component.ts

@ -14,22 +14,21 @@
/// limitations under the License.
///
import {AfterViewInit, Component, ElementRef, forwardRef, Input, OnInit, ViewChild} from '@angular/core';
import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR} from '@angular/forms';
import {Observable, of} from 'rxjs';
import {PageLink} from '@shared/models/page/page-link';
import {Direction} from '@shared/models/page/sort-order';
import {map, mergeMap, startWith, tap} from 'rxjs/operators';
import {PageData, emptyPageData} from '@shared/models/page/page-data';
import {DashboardInfo} from '@app/shared/models/dashboard.models';
import {DashboardId} from '@app/shared/models/id/dashboard-id';
import {DashboardService} from '@core/http/dashboard.service';
import {Store} from '@ngrx/store';
import {AppState} from '@app/core/core.state';
import {getCurrentAuthUser} from '@app/core/auth/auth.selectors';
import {Authority} from '@shared/models/authority.enum';
import {TranslateService} from '@ngx-translate/core';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order';
import { map, mergeMap, startWith, tap } from 'rxjs/operators';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { DashboardInfo } from '@app/shared/models/dashboard.models';
import { DashboardService } from '@core/http/dashboard.service';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { getCurrentAuthUser } from '@app/core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
import { TranslateService } from '@ngx-translate/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@Component({
selector: 'tb-dashboard-autocomplete',

2
ui-ngx/src/app/shared/components/dashboard-select.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<mat-select fxHide.xs fxHide.sm fxHide.md
<mat-select fxHide.lt-lg
[required]="required"
[disabled]="disabled"
[(ngModel)]="dashboardId"

2
ui-ngx/src/app/shared/components/dialog/todo-dialog.component.ts

@ -24,7 +24,7 @@ import { MatDialogRef } from '@angular/material/dialog';
})
export class TodoDialogComponent {
comingSoon = require('../../../../assets/coming-soon.jpg');
comingSoon = require('../../../../assets/coming-soon.jpg').default;
constructor(public dialogRef: MatDialogRef<TodoDialogComponent>) {
}

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

@ -14,39 +14,18 @@
/// limitations under the License.
///
import {
AfterContentInit,
AfterViewInit,
Component,
ElementRef,
forwardRef,
Input,
OnInit,
SkipSelf,
ViewChild
} from '@angular/core';
import {
ControlValueAccessor,
FormBuilder,
FormControl,
FormGroup,
FormGroupDirective,
NG_VALUE_ACCESSOR, NgForm, Validators
} from '@angular/forms';
import {Observable, of} from 'rxjs';
import {map, mergeMap, startWith, tap, share, pairwise, filter} from 'rxjs/operators';
import {Store} from '@ngrx/store';
import {AppState} from '@app/core/core.state';
import {TranslateService} from '@ngx-translate/core';
import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { filter, map, mergeMap, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { AliasEntityType, EntityType, entityTypeTranslations } from '@shared/models/entity-type.models';
import {BaseData} from '@shared/models/base-data';
import {EntityId} from '@shared/models/id/entity-id';
import {EntityService} from '@core/http/entity.service';
import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { EntityService } from '@core/http/entity.service';
import { MatAutocomplete } from '@angular/material/autocomplete';
import { MatChipList } from '@angular/material/chips';
import { ErrorStateMatcher } from '@angular/material/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { emptyPageData } from '@shared/models/page/page-data';
interface EntityTypeInfo {
name: string;

11
ui-ngx/src/app/shared/components/fab-toolbar.component.ts

@ -15,19 +15,20 @@
///
import {
AfterViewInit,
Component,
Directive,
ElementRef,
Inject,
Input,
OnChanges,
OnDestroy,
OnInit,
Renderer2,
ViewEncapsulation,
SimpleChanges,
Inject, AfterViewInit, AfterViewChecked, Directive, OnDestroy
ViewEncapsulation
} from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { WINDOW } from '@core/services/window.service';
import { mixinColor, CanColorCtor } from '@angular/material/core';
import { CanColorCtor, mixinColor } from '@angular/material/core';
export declare type FabToolbarDirection = 'left' | 'right';

1
ui-ngx/src/app/shared/components/json-form/react/json-form-checkbox.tsx

@ -33,7 +33,6 @@ class ThingsboardCheckbox extends React.Component<JsonFormFieldProps, JsonFormFi
onChange={(e, checked) => {
this.props.onChangeValidate(e);
}}
style={{paddingTop: '14px'}}
/>
}
label={this.props.form.title}

7
ui-ngx/src/app/shared/components/led-light.component.ts

@ -16,6 +16,7 @@
import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { RaphaelElement, RaphaelPaper, RaphaelSet } from 'raphael';
import Raphael from 'raphael';
import * as tinycolor_ from 'tinycolor2';
@ -38,7 +39,7 @@ export class LedLightComponent implements OnInit, AfterViewInit, OnChanges {
@Input() colorOff: string;
@Input() offOpacity: string;
@Input() offOpacity: number;
private enabledValue: boolean;
get enabled(): boolean {
@ -61,7 +62,7 @@ export class LedLightComponent implements OnInit, AfterViewInit, OnChanges {
}
ngOnInit(): void {
this.offOpacity = this.offOpacity || '0.4';
this.offOpacity = this.offOpacity || 0.4;
this.glowColor = tinycolor(this.colorOn).lighten().toHexString();
}
@ -100,7 +101,7 @@ export class LedLightComponent implements OnInit, AfterViewInit, OnChanges {
if (this.enabled) {
this.circleElement.attr('fill', this.colorOn);
this.circleElement.attr('stroke', this.colorOn);
this.circleElement.attr('opacity', '1');
this.circleElement.attr('opacity', 1);
if (this.circleElement.theGlow) {
this.circleElement.theGlow.remove();
}

2
ui-ngx/src/app/shared/components/logo.component.ts

@ -23,7 +23,7 @@ import { Component } from '@angular/core';
})
export class LogoComponent {
logo = require('../../../assets/logo_title_white.svg');
logo = require('../../../assets/logo_title_white.svg').default;
gotoThingsboard(): void {
window.open('https://thingsboard.io', '_blank');

2
ui-ngx/src/app/shared/components/material-icon-select.component.html

@ -17,7 +17,7 @@
-->
<div fxLayout="row" [formGroup]="materialIconFormGroup">
<mat-icon (click)="openIconDialog()">{{materialIconFormGroup.get('icon').value}}</mat-icon>
<mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>icon.icon</mat-label>
<input matInput formControlName="icon" (mousedown)="openIconDialog()">
</mat-form-field>

6
ui-ngx/src/app/shared/components/material-icon-select.component.scss

@ -21,3 +21,9 @@
border: solid 1px rgba(0, 0, 0, .27);
}
}
:host ::ng-deep {
.mat-form-field-infix{
width: 146px;
}
}

24
ui-ngx/src/app/shared/components/material-icon-select.component.ts

@ -14,31 +14,11 @@
/// limitations under the License.
///
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { DataKey, DatasourceType } from '@shared/models/widget.models';
import {
ControlValueAccessor,
FormBuilder,
FormControl,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
Validator,
Validators
} from '@angular/forms';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { MatDialog } from '@angular/material/dialog';
import { EntityService } from '@core/http/entity.service';
import { DataKeysCallbacks } from '@home/components/widget/data-keys.component.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { Observable, of } from 'rxjs';
import { map, mergeMap, tap } from 'rxjs/operators';
import { alarmFields } from '@shared/models/alarm.models';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { DialogService } from '@core/services/dialog.service';
@Component({

2
ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html

@ -24,7 +24,7 @@
[matAutocomplete]="relationTypeAutocomplete">
<button *ngIf="relationTypeFormGroup.get('relationType').value && !disabled"
type="button"
matSuffix mat-button mat-icon-button aria-label="Clear"
matSuffix mat-icon-button aria-label="Clear"
(click)="clear()">
<mat-icon class="material-icons">close</mat-icon>
</button>

28
ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts

@ -14,27 +14,15 @@
/// limitations under the License.
///
import {AfterViewInit, Component, ElementRef, forwardRef, Input, OnInit, ViewChild, OnDestroy} from '@angular/core';
import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import {Observable, of, throwError, Subscription} from 'rxjs';
import {PageLink} from '@shared/models/page/page-link';
import {Direction} from '@shared/models/page/sort-order';
import {filter, map, mergeMap, publishReplay, refCount, startWith, tap, publish} from 'rxjs/operators';
import {PageData, emptyPageData} from '@shared/models/page/page-data';
import {DashboardInfo} from '@app/shared/models/dashboard.models';
import {DashboardId} from '@app/shared/models/id/dashboard-id';
import {DashboardService} from '@core/http/dashboard.service';
import {Store} from '@ngrx/store';
import {AppState} from '@app/core/core.state';
import {getCurrentAuthUser} from '@app/core/auth/auth.selectors';
import {Authority} from '@shared/models/authority.enum';
import {TranslateService} from '@ngx-translate/core';
import {DeviceService} from '@core/http/device.service';
import {EntitySubtype, EntityType} from '@app/shared/models/entity-type.models';
import {BroadcastService} from '@app/core/services/broadcast.service';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {AssetService} from '@core/http/asset.service';
import {EntityViewService} from '@core/http/entity-view.service';
import { Observable, of } from 'rxjs';
import { map, mergeMap, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { BroadcastService } from '@app/core/services/broadcast.service';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { RelationTypes } from '@app/shared/models/relation.models';
@Component({

8
ui-ngx/src/app/shared/components/socialshare-panel.component.html

@ -16,7 +16,7 @@
-->
<div fxLayout="row" fxLayoutGap="12px" [fxHide]="isShareLinkLocal()">
<button mat-button mat-icon-button mat-raised-button class="mat-primary"
<button mat-icon-button mat-raised-button class="mat-primary"
shareButton="facebook"
title="{{ shareTitle }}"
description="{{ shareText }}"
@ -25,7 +25,7 @@
matTooltip="{{ 'action.share-via' | translate:{provider:'Facebook'} }}">
<mat-icon svgIcon="mdi:facebook"></mat-icon>
</button>
<button mat-button mat-icon-button mat-raised-button class="mat-primary"
<button mat-icon-button mat-raised-button class="mat-primary"
shareButton="twitter"
title="{{ shareTitle }}"
tags="{{ shareHashTags }}"
@ -34,7 +34,7 @@
matTooltip="{{ 'action.share-via' | translate:{provider:'Twitter'} }}">
<mat-icon svgIcon="mdi:twitter"></mat-icon>
</button>
<button mat-button mat-icon-button mat-raised-button class="mat-primary"
<button mat-icon-button mat-raised-button class="mat-primary"
shareButton="linkedin"
title="{{ shareTitle }}"
url="{{ shareLink }}"
@ -42,7 +42,7 @@
matTooltip="{{ 'action.share-via' | translate:{provider:'Linkedin'} }}">
<mat-icon svgIcon="mdi:linkedin"></mat-icon>
</button>
<button mat-button mat-icon-button mat-raised-button class="mat-primary"
<button mat-icon-button mat-raised-button class="mat-primary"
shareButton="reddit"
title="{{ shareTitle }}"
url="{{ shareLink }}"

12
ui-ngx/src/app/shared/components/socialshare-panel.component.ts

@ -14,16 +14,8 @@
/// limitations under the License.
///
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { User } from '@shared/models/user.model';
import { Authority } from '@shared/models/authority.enum';
import { select, Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { selectAuthUser, selectUserDetails } from '@core/auth/auth.selectors';
import { map } from 'rxjs/operators';
import { AuthService } from '@core/auth/auth.service';
import { Router } from '@angular/router';
import {isLocalUrl} from '@core/utils';
import { Component, Input, OnInit } from '@angular/core';
import { isLocalUrl } from '@core/utils';
@Component({
selector: 'tb-social-share-panel',

1
ui-ngx/src/styles.scss

@ -863,6 +863,7 @@ mat-label {
.mat-dialog-container {
> *:first-child, form {
min-width: 100% !important;
height: 100vh;
}
.mat-dialog-content {
max-height: 100%;

18
ui/src/app/common/types.constant.js

@ -606,13 +606,29 @@ export default angular.module('thingsboard.types', [])
value: "modbus",
name: "Modbus"
},
opc_ua: {
opcua: {
value: "opcua",
name: "OPC-UA"
},
ble: {
value: "ble",
name: "BLE"
},
request: {
value: "request",
name: "Request"
},
can: {
value: "can",
name: "CAN"
},
bacnet: {
value: "bacnet",
name: "BACnet"
},
custom: {
value: "custom",
name: "Custom"
}
},
gatewayLogLevel: {

7
ui/src/app/components/gateway/gateway-config.directive.js

@ -37,7 +37,8 @@ function GatewayConfig() {
disabled: '=ngDisabled',
gatewayConfig: '=',
changeAlignment: '=',
theForm: '='
theForm: '=',
isReadOnly: '='
},
controller: GatewayConfigController,
controllerAs: 'vm',
@ -83,6 +84,10 @@ function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window,
multiple: true,
}).then(function (config) {
if (config && index > -1) {
console.log(config); //eslint-disable-line
if (!angular.equals(vm.gatewayConfig[index].config, config)) {
$scope.gatewayConfiguration.$setDirty();
}
vm.gatewayConfig[index].config = config;
}
});

12
ui/src/app/components/gateway/gateway-config.tpl.html

@ -18,7 +18,7 @@
<section name="gatewayConfig" layout="column" class="gateway-config">
<section layout="row" ng-form="gatewayConfig_{{$index}}" ng-repeat="connector in vm.gatewayConfig track by $index">
<div layout="column" layout-align="center start" class="gateway-config-row">
<md-switch ng-model="connector.enabled" ng-disabled="gatewayConfig_{{$index}}.$invalid || vm.validateJSON(connector.config)"
<md-switch ng-disabled="vm.isReadOnly" ng-model="connector.enabled" ng-disabled="gatewayConfig_{{$index}}.$invalid || vm.validateJSON(connector.config)"
aria-label="{{ 'gateway.connector-enabled' | translate }}">
</md-switch>
</div>
@ -26,7 +26,7 @@
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-input-container class="md-block" flex>
<label>{{'gateway.connector-type' | translate }}</label>
<md-select name="connectorType"
<md-select ng-disabled="vm.isReadOnly" name="connectorType"
ng-change="vm.changeConnectorType(connector)"
aria-label="{{ 'gateway.gateway.connector-type' | translate }}"
ng-model="connector.configType" required>
@ -39,7 +39,7 @@
</div>
</md-input-container>
<md-input-container class="md-block" flex>
<input placeholder="{{'gateway.connector-name' | translate }}"
<input ng-disabled="vm.isReadOnly" placeholder="{{'gateway.connector-name' | translate }}"
ng-model-options="{ updateOn: 'blur' }"
ng-change="vm.changeConnectorName(connector, $index)" name="connectorName" ng-model="connector.name" required/>
<div ng-messages="vm.theForm.connectorName.$error">
@ -49,7 +49,7 @@
</div>
<div layout="row" layout-align="end center" class="action-buttons"
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-button class="md-icon-button md-mini" ng-click="vm.openConfigDialog($event, $index, connector.config, connector.name)"
<md-button ng-disabled="vm.isReadOnly" class="md-icon-button md-mini" ng-click="vm.openConfigDialog($event, $index, connector.config, connector.name)"
aria-label="{{ 'gateway.update-config' | translate }}"
ng-class="{'md-warn': vm.validateJSON(connector.config)}">
<md-icon class="material-icons">more_horiz</md-icon>
@ -57,7 +57,7 @@
{{ 'gateway.update-config' | translate }}
</md-tooltip>
</md-button>
<md-button class="md-icon-button md-mini" ng-click="vm.removeConnector($index)"
<md-button ng-disabled="vm.isReadOnly" class="md-icon-button md-mini" ng-click="vm.removeConnector($index)"
aria-label="{{ 'gateway.delete' | translate }}">
<md-icon class="material-icons">close</md-icon>
<md-tooltip md-direction="top">
@ -70,7 +70,7 @@
layout-align="center center" ng-class="{'disabled': vm.disabled}"
class="no-data-found" translate>{{'gateway.no-connectors'}}</span>
<div>
<md-button class="md-raised" ng-click="vm.addNewConnector()"
<md-button ng-show="!vm.isReadOnly" class="md-raised" ng-click="vm.addNewConnector()"
aria-label="{{ 'gateway.connector-add' | translate }}">
<md-tooltip md-direction="top">
{{ 'gateway.connector-add' | translate }}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save