Browse Source

Merge pull request #74 from deaflynx/develop/2.6-edge

Develop/2.6 edge Edges overview widget, languages update, hide sensitive info for customers
pull/3957/head
VoBa 5 years ago
committed by GitHub
parent
commit
9dce6f3e5d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      application/src/main/data/json/system/widget_bundles/edge_widgets.json
  2. 1
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  3. 74
      ui/src/app/api/component-descriptor.service.js
  4. 25
      ui/src/app/api/entity.service.js
  5. 3
      ui/src/app/api/widget.service.js
  6. 6
      ui/src/app/components/nav-tree.scss
  7. 2
      ui/src/app/customer/customer-fieldset.tpl.html
  8. 44
      ui/src/app/customer/customer.controller.js
  9. 8
      ui/src/app/edge/downlinks/edge-downlinks-row.directive.js
  10. 23
      ui/src/app/edge/edge-fieldset.tpl.html
  11. 3
      ui/src/app/edge/edge.directive.js
  12. 59
      ui/src/app/edge/edge.routes.js
  13. 2
      ui/src/app/edge/edges.tpl.html
  14. 67
      ui/src/app/locale/locale.constant-de_DE.json
  15. 6
      ui/src/app/locale/locale.constant-en_US.json
  16. 69
      ui/src/app/locale/locale.constant-es_ES.json
  17. 67
      ui/src/app/locale/locale.constant-fr_FR.json
  18. 9
      ui/src/app/rulechain/rulechain-fieldset.tpl.html
  19. 2
      ui/src/app/rulechain/rulechain.controller.js
  20. 1
      ui/src/app/rulechain/rulechain.directive.js
  21. 6
      ui/src/app/rulechain/rulechain.routes.js
  22. 46
      ui/src/app/rulechain/rulechains.controller.js
  23. 1
      ui/src/app/rulechain/rulechains.tpl.html
  24. 4
      ui/src/app/services/menu.service.js
  25. 240
      ui/src/app/widget/lib/edges-overview-widget.js
  26. 60
      ui/src/app/widget/lib/edges-overview-widget.scss
  27. 29
      ui/src/app/widget/lib/edges-overview-widget.tpl.html

25
application/src/main/data/json/system/widget_bundles/edge_widgets.json

@ -0,0 +1,25 @@
{
"widgetsBundle": {
"alias": "edge_widgets",
"title": "Edge widgets",
"image": null
},
"widgetTypes": [
{
"alias": "edges_overview",
"name": "Edges Quick Overview",
"descriptor": {
"type": "latest",
"sizeX": 7.5,
"sizeY": 5,
"resources": [],
"templateHtml": "<tb-edges-overview-widget \n ctx=\"ctx\">\n</tb-edges-overview-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'nodeSelected': {\n name: 'widget-action.node-selected',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{},\"title\":\"Edges Quick Overview\",\"showTitleIcon\":true,\"titleIcon\":\"router\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"widgetStyle\":{},\"actions\":{}}"
}
}
]
}

1
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -176,6 +176,7 @@ public class ThingsboardInstallService {
systemDataLoaderService.deleteSystemWidgetBundle("input_widgets");
systemDataLoaderService.deleteSystemWidgetBundle("date");
systemDataLoaderService.deleteSystemWidgetBundle("entity_admin_widgets");
systemDataLoaderService.deleteSystemWidgetBundle("edge_widgets");
systemDataLoaderService.loadSystemWidgets();
break;

74
ui/src/app/api/component-descriptor.service.js

@ -21,38 +21,63 @@ function ComponentDescriptorService($http, $q) {
var componentsByType = {};
var componentsByClazz = {};
var actionsByPlugin = {};
var service = {
getComponentDescriptorsByType: getComponentDescriptorsByType,
getComponentDescriptorByClazz: getComponentDescriptorByClazz,
getPluginActionsByPluginClazz: getPluginActionsByPluginClazz,
getComponentDescriptorsByTypes: getComponentDescriptorsByTypes
}
return service;
function getComponentDescriptorsByTypes(componentTypes, ruleChainType) {
function getComponentDescriptorsByType(componentType) {
var deferred = $q.defer();
if (componentsByType[componentType]) {
deferred.resolve(componentsByType[componentType]);
} else {
var url = '/api/components/' + componentType;
$http.get(url, null).then(function success(response) {
componentsByType[componentType] = response.data;
for (var i = 0; i < componentsByType[componentType].length; i++) {
var component = componentsByType[componentType][i];
componentsByClazz[component.clazz] = component;
}
deferred.resolve(componentsByType[componentType]);
}, function fail() {
deferred.reject();
});
}
return deferred.promise;
}
function getComponentDescriptorsByTypes(componentTypes, type) {
var deferred = $q.defer();
var result = [];
if (!componentsByType[ruleChainType]) {
componentsByType[ruleChainType] = {};
if (!componentsByType[type]) {
componentsByType[type] = {};
}
for (var i=componentTypes.length-1;i>=0;i--) {
var componentType = componentTypes[i];
if (componentsByType[ruleChainType][componentType]) {
result = result.concat(componentsByType[ruleChainType][componentType]);
if (componentsByType[type][componentType]) {
result = result.concat(componentsByType[type][componentType]);
componentTypes.splice(i, 1);
}
}
if (!componentTypes.length) {
deferred.resolve(result);
} else {
var url = '/api/components?componentTypes=' + componentTypes.join(',') + '&ruleChainType=' + ruleChainType;
var url = '/api/components?componentTypes=' + componentTypes.join(',') + '&ruleChainType=' + type;
$http.get(url, null).then(function success(response) {
var components = response.data;
for (var i = 0; i < components.length; i++) {
var component = components[i];
var componentsList = componentsByType[ruleChainType][component.type];
var componentsList = componentsByType[type][component.type];
if (!componentsList) {
componentsList = [];
componentsByType[ruleChainType][component.type] = componentsList;
componentsByType[type][component.type] = componentsList;
}
componentsList.push(component);
componentsByClazz[component.clazz] = component;
@ -65,4 +90,37 @@ function ComponentDescriptorService($http, $q) {
}
return deferred.promise;
}
function getComponentDescriptorByClazz(componentDescriptorClazz) {
var deferred = $q.defer();
if (componentsByClazz[componentDescriptorClazz]) {
deferred.resolve(componentsByClazz[componentDescriptorClazz]);
} else {
var url = '/api/component/' + componentDescriptorClazz;
$http.get(url, null).then(function success(response) {
componentsByClazz[componentDescriptorClazz] = response.data;
deferred.resolve(componentsByClazz[componentDescriptorClazz]);
}, function fail() {
deferred.reject();
});
}
return deferred.promise;
}
function getPluginActionsByPluginClazz(pluginClazz) {
var deferred = $q.defer();
if (actionsByPlugin[pluginClazz]) {
deferred.resolve(actionsByPlugin[pluginClazz]);
} else {
var url = '/api/components/actions/' + pluginClazz;
$http.get(url, null).then(function success(response) {
actionsByPlugin[pluginClazz] = response.data;
deferred.resolve(actionsByPlugin[pluginClazz]);
}, function fail() {
deferred.reject();
});
}
return deferred.promise;
}
}

25
ui/src/app/api/entity.service.js

@ -42,7 +42,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
getRelatedEntity: getRelatedEntity,
deleteRelatedEntity: deleteRelatedEntity,
moveEntity: moveEntity,
copyEntity: copyEntity
copyEntity: copyEntity,
getAssignedToEdgeEntitiesByType: getAssignedToEdgeEntitiesByType
};
return service;
@ -1684,4 +1685,26 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
}
}
function getAssignedToEdgeEntitiesByType(edgeId, entityType, pageLink) {
var promise;
switch (entityType) {
case types.entityType.device:
promise = deviceService.getEdgeDevices(edgeId, pageLink, null);
break;
case types.entityType.asset:
promise = assetService.getEdgeAssets(edgeId, pageLink, null);
break;
case types.entityType.entityView:
promise = entityViewService.getEdgeEntityViews(edgeId, pageLink, null);
break;
case types.entityType.dashboard:
promise = dashboardService.getEdgeDashboards(edgeId, pageLink, null);
break;
case types.entityType.rulechain:
promise = ruleChainService.getEdgeRuleChains(edgeId, pageLink, null);
break;
}
return promise;
}
}

3
ui/src/app/api/widget.service.js

@ -22,6 +22,7 @@ import thingsboardTimeseriesTableWidget from '../widget/lib/timeseries-table-wid
import thingsboardAlarmsTableWidget from '../widget/lib/alarms-table-widget';
import thingsboardEntitiesTableWidget from '../widget/lib/entities-table-widget';
import thingsboardEntitiesHierarchyWidget from '../widget/lib/entities-hierarchy-widget';
import thingsboardEdgesOverviewWidget from '../widget/lib/edges-overview-widget'
import thingsboardExtensionsTableWidget from '../widget/lib/extensions-table-widget';
import thingsboardDateRangeNavigatorWidget from '../widget/lib/date-range-navigator/date-range-navigator';
import thingsboardMultipleInputWidget from '../widget/lib/multiple-input-widget';
@ -52,7 +53,7 @@ import thingsboardUtils from '../common/utils.service';
export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsboardLedLight,
thingsboardTimeseriesTableWidget, thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget,
thingsboardEntitiesHierarchyWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget,
thingsboardEntitiesHierarchyWidget, thingsboardEdgesOverviewWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget,
thingsboardMultipleInputWidget, thingsboardWebCameraInputWidget, thingsboardRpcWidgets, thingsboardTypes,
thingsboardUtils, thingsboardJsonToString, TripAnimationWidget])
.factory('widgetService', WidgetService)

6
ui/src/app/components/nav-tree.scss

@ -131,6 +131,12 @@
content: "supervisor_account";
}
}
&.tb-rule-chain-group {
&::before {
content: "settings_ethernet";
}
}
}
}
}

2
ui/src/app/customer/customer-fieldset.tpl.html

@ -19,7 +19,7 @@
<md-button ng-click="onManageAssets({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-assets' | translate }}</md-button>
<md-button ng-click="onManageDevices({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-devices' | translate }}</md-button>
<md-button ng-click="onManageDashboards({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-dashboards' | translate }}</md-button>
<md-button ng-click="onManageEdges({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-edges' | translate }}</md-button>
<md-button ng-click="onManageEdges({event: $event})" ng-show="!isEdit && vm.isEdgesSupportEnabled" class="md-raised md-primary">{{ 'customer.manage-edges' | translate }}</md-button>
<md-button ng-click="onDeleteCustomer({event: $event})" ng-show="!isEdit && !isPublic" class="md-raised md-primary">{{ 'customer.delete' | translate }}</md-button>
<div layout="row">

44
ui/src/app/customer/customer.controller.js

@ -21,7 +21,7 @@ import customerCard from './customer-card.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
export default function CustomerController(customerService, $state, $stateParams, $translate, types) {
export default function CustomerController(customerService, $state, $stateParams, $translate, types, userService) {
var customerActionsList = [
{
@ -76,21 +76,29 @@ export default function CustomerController(customerService, $state, $stateParams
}
},
icon: "dashboard"
},
{
onAction: function ($event, item) {
openCustomerEdges($event, item);
},
name: function() { return $translate.instant('edge.edge-instances') },
details: function(customer) {
if (customer && customer.additionalInfo && customer.additionalInfo.isPublic) {
return $translate.instant('customer.manage-public-edges')
} else {
return $translate.instant('customer.manage-customer-edges')
}
},
icon: "router"
},
}];
if (userService.isEdgesSupportEnabled()) {
customerActionsList.push(
{
onAction: function ($event, item) {
openCustomerEdges($event, item);
},
name: function() { return $translate.instant('edge.edge-instances') },
details: function(customer) {
if (customer && customer.additionalInfo && customer.additionalInfo.isPublic) {
return $translate.instant('customer.manage-public-edges')
} else {
return $translate.instant('customer.manage-customer-edges')
}
},
icon: "router",
isEnabled: false
}
)
}
customerActionsList.push(
{
onAction: function ($event, item) {
vm.grid.deleteItem($event, item);
@ -102,12 +110,14 @@ export default function CustomerController(customerService, $state, $stateParams
return customer && (!customer.additionalInfo || !customer.additionalInfo.isPublic);
}
}
];
);
var vm = this;
vm.types = types;
vm.isEdgesSupportEnabled = userService.isEdgesSupportEnabled();
vm.customerGridConfig = {
refreshParamsFunc: null,

8
ui/src/app/edge/downlinks/edge-downlinks-row.directive.js

@ -92,14 +92,6 @@ export default function EdgeDownlinksRowDirective($compile, $templateCache, $mdD
type === types.edgeEventType.widgetsBundle );
}
scope.checkTooltip = function($event) {
var el = $event.target;
var $el = angular.element(el);
if(el.offsetWidth < el.scrollWidth && !$el.attr('title')){
$el.attr('title', $el.text());
}
}
$compile(element.contents())(scope);
scope.updateStatus = function(downlinkCreatedTime) {

23
ui/src/app/edge/edge-fieldset.tpl.html

@ -44,7 +44,7 @@
class="md-raised md-primary">{{ 'edge.dashboards' | translate }}</md-button>
<md-button ng-click="onManageEdgeRuleChains({event: $event})"
ng-show="!isEdit && edgeScope === 'tenant'"
class="md-raised md-primary">{{ 'edge.rulechain-templates' | translate }}</md-button>
class="md-raised md-primary">{{ 'edge.manage-edge-rulechains' | translate }}</md-button>
</div>
<div layout="row">
@ -57,20 +57,25 @@
</md-button>
<md-button ngclipboard data-clipboard-action="copy"
ngclipboard-success="onEdgeInfoCopied('key')"
data-clipboard-text="{{edge.routingKey}}" ng-show="!isEdit"
data-clipboard-text="{{edge.routingKey}}"
ng-show="!isEdit"
ng-if="isTenantAdmin"
class="md-raised">
<md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
<span translate>edge.copy-edge-key</span>
</md-button>
<md-button ngclipboard data-clipboard-action="copy"
ngclipboard-success="onEdgeInfoCopied('secret')"
data-clipboard-text="{{edge.secret}}" ng-show="!isEdit"
data-clipboard-text="{{edge.secret}}"
ng-show="!isEdit"
ng-if="isTenantAdmin"
class="md-raised">
<md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
<span translate>edge.copy-edge-secret</span>
</md-button>
<md-button ng-click="onEdgeSync(edge.id)"
ng-show="!isEdit"
ng-if="isTenantAdmin"
class="md-raised">
<md-icon md-svg-icon="mdi:sync"></md-icon>
<span translate>edge.sync</span>
@ -102,16 +107,16 @@
ng-model="edge.type"
entity-type="types.entityType.edge">
</tb-entity-subtype-autocomplete>
<div translate class="tb-hint">edge.license-key-hint</div>
<md-input-container class="md-block">
<div translate class="tb-hint" ng-if="isTenantAdmin">edge.license-key-hint</div>
<md-input-container class="md-block" ng-if="isTenantAdmin">
<label translate>edge.edge-license-key</label>
<input required name="edgeLicenseKey" ng-model="edge.edgeLicenseKey">
<div ng-messages="theForm.edgeLicenseKey.$error">
<div translate ng-message="required">edge.edge-license-key-required</div>
</div>
</md-input-container>
<div translate class="tb-hint">edge.cloud-endpoint-hint</div>
<md-input-container class="md-block">
<div translate class="tb-hint" ng-if="isTenantAdmin">edge.cloud-endpoint-hint</div>
<md-input-container class="md-block" ng-if="isTenantAdmin">
<label translate>edge.cloud-endpoint</label>
<input required name="cloudEndpoint" ng-model="edge.cloudEndpoint">
<div ng-messages="theForm.cloudEndpoint.$error">
@ -119,7 +124,7 @@
</div>
</md-input-container>
</fieldset>
<div layout="row">
<div layout="row" ng-if="isTenantAdmin">
<md-input-container class="md-block" flex>
<label translate>edge.edge-key</label>
<input ng-model="edge.routingKey" disabled>
@ -134,7 +139,7 @@
</md-tooltip>
</md-button>
</div>
<div layout="row">
<div layout="row" ng-if="isTenantAdmin">
<md-input-container class="md-block" flex>
<label translate>edge.edge-secret</label>
<input ng-model="edge.secret" disabled>

3
ui/src/app/edge/edge.directive.js

@ -20,7 +20,7 @@ import edgeFieldsetTemplate from './edge-fieldset.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
export default function EdgeDirective($compile, $templateCache, $translate, $mdDialog, $document, utils, toast, types, customerService, edgeService) {
export default function EdgeDirective($compile, $templateCache, $translate, $mdDialog, $document, utils, toast, types, customerService, edgeService, userService) {
var linker = function (scope, element) {
var template = $templateCache.get(edgeFieldsetTemplate);
element.html(template);
@ -29,6 +29,7 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD
scope.isAssignedToCustomer = false;
scope.isPublic = false;
scope.assignedCustomer = null;
scope.isTenantAdmin = userService.getCurrentUser().authority === 'TENANT_ADMIN';
scope.$watch('edge', function(newVal) {
if (newVal) {

59
ui/src/app/edge/edge.routes.js

@ -21,8 +21,6 @@ import devicesTemplate from "../device/devices.tpl.html";
import assetsTemplate from "../asset/assets.tpl.html";
import dashboardsTemplate from "../dashboard/dashboards.tpl.html";
import dashboardTemplate from "../dashboard/dashboard.tpl.html";
import ruleChainsTemplate from "../rulechain/rulechains.tpl.html";
import ruleChainTemplate from "../rulechain/rulechain.tpl.html";
/* eslint-enable import/no-unresolved, import/default */
@ -180,62 +178,5 @@ export default function EdgeRoutes($stateProvider, types) {
ncyBreadcrumb: {
label: '{"icon": "router", "label": "{{ vm.customerEdgesTitle }}", "translate": "false"}'
}
}).state('home.edges.ruleChains', {
url: '/:edgeId/ruleChains',
params: {'topIndex': 0},
module: 'private',
auth: ['TENANT_ADMIN'],
views: {
"content@home": {
templateUrl: ruleChainsTemplate,
controllerAs: 'vm',
controller: 'RuleChainsController'
}
},
data: {
searchEnabled: true,
pageTitle: 'edge.rulechain-templates',
ruleChainsType: 'edge'
},
ncyBreadcrumb: {
label: '{"icon": "settings_ethernet", "label": "edge.rulechain-templates"}'
}
}).state('home.edges.ruleChains.ruleChain', {
url: '/:ruleChainId',
reloadOnSearch: false,
module: 'private',
auth: ['SYS_ADMIN', 'TENANT_ADMIN'],
views: {
"content@home": {
templateUrl: ruleChainTemplate,
controller: 'RuleChainController',
controllerAs: 'vm'
}
},
resolve: {
ruleChain:
/*@ngInject*/
function($stateParams, ruleChainService) {
return ruleChainService.getRuleChain($stateParams.ruleChainId);
},
ruleChainMetaData:
/*@ngInject*/
function($stateParams, ruleChainService) {
return ruleChainService.getRuleChainMetaData($stateParams.ruleChainId);
},
ruleNodeComponents:
/*@ngInject*/
function($stateParams, ruleChainService) {
return ruleChainService.getRuleNodeComponents(types.ruleChainType.edge);
}
},
data: {
import: false,
searchEnabled: false,
pageTitle: 'edge.rulechain-templates'
},
ncyBreadcrumb: {
label: '{"icon": "settings_ethernet", "label": "{{ vm.ruleChain.name }}", "translate": "false"}'
}
});
}

2
ui/src/app/edge/edges.tpl.html

@ -65,7 +65,7 @@
default-event-type="{{vm.types.eventType.error.value}}">
</tb-event-table>
</md-tab>
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.downlinks' | translate }}">
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.isTenantAdmin()" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.downlinks' | translate }}">
<tb-edge-downlinks-table flex entity-type="vm.types.entityType.edge"
entity-id="vm.grid.operatingItem().id.id"
tenant-id="vm.grid.operatingItem().tenantId.id">

67
ui/src/app/locale/locale.constant-de_DE.json

@ -811,7 +811,66 @@
"event-action": "Ereignisaktion",
"load-entity-error": "Entität nicht gefunden. Fehler beim Laden der Informationen",
"unassign-edges-text": "Nach der Bestätigung werden alle ausgewählten Kanten nicht zugewiesen und sind für den Kunden nicht zugänglich.",
"unassign-edges-title": "Sind Sie sicher, dass Sie die Zuordnung aufheben möchten { count, plural, 1 {1 Rand} other {# Rand} }?"
"unassign-edges-title": "Sind Sie sicher, dass Sie die Zuordnung aufheben möchten { count, plural, 1 {1 Rand} other {# Rand} }?",
"edge-file": "Edge-Datei",
"name-starts-with": "Der Kantenname beginnt mit",
"rulechain-templates": "Regelkettenvorlagen",
"rulechain-template": "Regelkettenvorlage",
"unassign-edges-action-title": "Heben Sie die Zuordnung von {count, plural, 1 {1 edge} other {# edge}} vom Kunden auf",
"enter-edge-type": "Geben Sie den Kantentyp ein",
"no-edge-types-matching": "Es wurden keine Kantentypen gefunden, die mit '{{entitySubtype}}' übereinstimmen.",
"edge-type-list-empty": "Keine Kantentypen ausgewählt.",
"edge-types": "Kantentypen",
"license-key-hint": "Um Ihre Lizenz zu erhalten, navigieren Sie zur <a href='https://thingsboard.io/pricing/?active=thingsboard-edge'arget='_blank'> Preisseite </a> und wählen Sie die beste Lizenzoption für Ihre aus Fall.",
"cloud-endpoint-hint": "Edge erfordert HTTP-Zugriff auf die Cloud (ThingsBoard CE / PE), um den Lizenzschlüssel zu überprüfen. Bitte geben Sie die Cloud-URL an, zu der Edge eine Verbindung herstellen kann.",
"missing-related-rule-chains-title": "In Edge fehlen verwandte Regelketten.",
"missing-related-rule-chains-text": "Randregelkette (n) zugewiesen Verwenden Sie Regelknoten, die Nachrichten an Regelkette (n) weiterleiten, die dieser Kante nicht zugeordnet sind. <br> <br> Liste der fehlenden Regelketten: <br> {{missingRuleChains}}",
"downlinks": "Downlinks",
"no-downlinks-prompt": "Keine Downlinks gefunden",
"assigned-to-customer-widget": "Zugewiesen an: {{customerTitle}}",
"widget-datasource-error": "Dieses Widget unterstützt nur EDGE-Entitätsdatenquellen"
},
"edge-event": {
"type-dashboard": "Dashboard",
"type-asset": "Asset",
"type-device": "Device",
"type-device-profile": "Device Profile",
"type-entity-view": "Entity View",
"type-alarm": "Alar",
"type-rule-chain": "Rule Chain",
"type-rule-chain-metadata": "Rule Chain Metadata",
"type-edge": "Edge",
"type-entity-group": "Entity Group",
"type-scheduler-event": "Scheduler Event",
"type-white-labeling": "White Labeling",
"type-login-white-labeling": "White Labeling Login",
"type-user": "User",
"type-tenant": "Tenant",
"type-customer": "Customer",
"type-custom-translation": "Custom Translation",
"type-relation": "Relation",
"type-widgets-bundle": "Widgets Bundle",
"type-widgets-type": "Widgets Type",
"type-admin-settings": "Admin Settings",
"action-type-added": "Added",
"action-type-deleted": "Deleted",
"action-type-updated": "Updated",
"action-type-post-attributes": "Post Attributes",
"action-type-attributes-updated": "Attributes Updated",
"action-type-attributes-deleted": "Attributes Deleted",
"action-type-timeseries-updated": "Timeseries Updated",
"action-type-credentials-updated": "Credentials Updated",
"action-type-assigned-to-customer": "Assigned to Customer",
"action-type-unassigned-from-customer": "Unassigned from Customer",
"action-type-relation-add-or-update": "Relation Add or Update",
"action-type-relation-deleted": "Relation Deleted",
"action-type-rpc-call": "RPC Call",
"action-type-alarm-ack": "Alarm Ack",
"action-type-alarm-clear": "Alarm Clear",
"action-type-assigned-to-edge": "Assigned to Edge",
"action-type-unassigned-from-edge": "Unassigned from Edge",
"action-type-credentials-request": "Credentials Request",
"action-type-entity-merge-request": "Entity Merge Request"
},
"error": {
"unable-to-connect": "Es konnte keine Verbindung zum Server hergestellt werden! Bitte überprüfen Sie Ihre Internetverbindung.",
@ -1409,7 +1468,11 @@
"unset-auto-assign-to-edge": "Weisen Sie Kanten bei der Erstellung keine Regelkette zu",
"unset-auto-assign-to-edge-title": "Sind Sie sicher, dass Sie die Kantenregelkette '{{ruleChainName}}' bei der Erstellung nicht den Kanten zuweisen möchten?",
"unset-auto-assign-to-edge-text": "Nach der Bestätigung wird die Kantenregelkette bei der Erstellung nicht mehr automatisch den Kanten zugewiesen.",
"edge-template-root": "Vorlagenstamm"
"edge-template-root": "Vorlagenstamm",
"set-auto-assign-to-edge-card": "Bei der Erstellung den Kanten zuweisen",
"set-default-root-edge": "Machen Sie die Regelkette zum Standardstamm",
"set-default-root-edge-rulechain-title": "Sind Sie sicher, dass Sie die Standardkettenwurzel der Regelkette '{{ruleChainName}}' festlegen möchten?",
"set-default-root-edge-rulechain-text": "Nach der Bestätigung wird die Regelkette zum Standard-Edge-Root und verarbeitet alle eingehenden Transportnachrichten."
},
"rulenode": {
"details": "Details",

6
ui/src/app/locale/locale.constant-en_US.json

@ -769,7 +769,6 @@
"management": "Edge management",
"no-edges-matching": "No edges matching '{{entity}}' were found.",
"add": "Add Edge",
"view": "View Edge",
"no-edges-text": "No edges found",
"edge-details": "Edge details",
"add-edge-text": "Add new edge",
@ -794,7 +793,6 @@
"id-copied-message": "Edge Id has been copied to clipboard",
"sync": "Sync Edge",
"sync-message": "Edge has been synchronized",
"permissions": "Permissions",
"edge-required": "Edge required",
"edge-type": "Edge type",
"edge-type-required": "Edge type is required.",
@ -856,7 +854,9 @@
"missing-related-rule-chains-title": "Edge has missing related rule chain(s)",
"missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge. <br><br> List of missing rule chain(s): <br> {{missingRuleChains}}",
"downlinks": "Downlinks",
"no-downlinks-prompt": "No downlinks found"
"no-downlinks-prompt": "No downlinks found",
"assigned-to-customer-widget": "Assigned to: {{customerTitle}}",
"widget-datasource-error": "This widget supports only EDGE entity datasource"
},
"edge-event": {
"type-dashboard": "Dashboard",

69
ui/src/app/locale/locale.constant-es_ES.json

@ -747,7 +747,6 @@
"management": "Gestión de bordes",
"no-edges-matching": "No se encontraron bordes que coincidan con '{{entity}}'",
"add": "Agregar borde",
"view": "Ver borde",
"no-edges-text": "No se encontraron bordes",
"edge-details": "Detalles del borde",
"add-edge-text": "Agregar nuevo borde",
@ -771,7 +770,6 @@
"id-copied-message": "El ID de borde se ha copiado al portapapeles",
"sync": "Sinc Edge",
"sync-message": "Edge se ha sincronizado",
"permissions": "Permisos",
"edge-required": "Edge required",
"edge-type": "Type de la bordure",
"edge-type-required": "El tipo de borde es requerido.",
@ -824,8 +822,67 @@
"event-action": "Información de la entidad",
"load-entity-error": "Entidad no encontrada. No se pudo cargar la información",
"unassign-edges-text": "Después de la confirmación de todos los bordes seleccionados, se anulará la asignación y el cliente no podrá acceder a ellos.",
"unassign-edges-title": "¿Está seguro de que desea anular la asignación de {count, plural, 1 {1 borde} other {# bordes}}?"
"unassign-edges-title": "¿Está seguro de que desea anular la asignación de {count, plural, 1 {1 borde} other {# bordes}}?",
"edge-file": "Archivo de borde",
"name-starts-with": "Edge name starts with",
"rulechain-templates": "Plantillas de cadena de reglas",
"rulechain-template": "Plantilla de cadena de reglas",
"unassign-edges-action-title": "Anular la asignación de {count, plural, 1 {1 borde} other {# bordes}} del cliente",
"enter-edge-type": "Ingrese el tipo de borde",
"no-edge-types-matching": "No se encontraron tipos de aristas que coincidan con '{{entitySubtype}}'.",
"edge-type-list-empty": "No se seleccionó ningún tipo de borde.",
"edge-types": "Tipos de bordes",
"license-key-hint": "Para obtener su licencia, vaya a la <a href='https://thingsboard.io/pricing/?active=thingsboard-edge' target='_blank'> página de precios </a> y seleccione la mejor opción de licencia para su caso.",
"cloud-endpoint-hint": "Edge requiere acceso HTTP (s) a la nube (ThingsBoard CE / PE) para verificar la clave de licencia. Especifique la URL de la nube a la que Edge puede conectarse.",
"missing-related-rule-chains-title": "Al borde le faltan cadenas de reglas relacionadas",
"missing-related-rule-chains-text": "Asignado a la (s) cadena (s) de reglas de borde usa nodos de reglas que reenvían mensajes a cadenas de reglas que no están asignadas a este borde. <br> <br> Lista de cadenas de reglas faltantes: <br> {{missingRuleChains}}",
"downlinks": "Enlaces descendentes",
"no-downlinks-prompt": "No se encontraron enlaces descendentes",
"assigned-to-customer-widget": "Asignado a: {{customerTitle}}",
"widget-datasource-error": "Este widget solo admite la fuente de datos de la entidad EDGE"
},
"edge-event": {
"type-dashboard": "Dashboard",
"type-asset": "Asset",
"type-device": "Device",
"type-device-profile": "Device Profile",
"type-entity-view": "Entity View",
"type-alarm": "Alar",
"type-rule-chain": "Rule Chain",
"type-rule-chain-metadata": "Rule Chain Metadata",
"type-edge": "Edge",
"type-entity-group": "Entity Group",
"type-scheduler-event": "Scheduler Event",
"type-white-labeling": "White Labeling",
"type-login-white-labeling": "White Labeling Login",
"type-user": "User",
"type-tenant": "Tenant",
"type-customer": "Customer",
"type-custom-translation": "Custom Translation",
"type-relation": "Relation",
"type-widgets-bundle": "Widgets Bundle",
"type-widgets-type": "Widgets Type",
"type-admin-settings": "Admin Settings",
"action-type-added": "Added",
"action-type-deleted": "Deleted",
"action-type-updated": "Updated",
"action-type-post-attributes": "Post Attributes",
"action-type-attributes-updated": "Attributes Updated",
"action-type-attributes-deleted": "Attributes Deleted",
"action-type-timeseries-updated": "Timeseries Updated",
"action-type-credentials-updated": "Credentials Updated",
"action-type-assigned-to-customer": "Assigned to Customer",
"action-type-unassigned-from-customer": "Unassigned from Customer",
"action-type-relation-add-or-update": "Relation Add or Update",
"action-type-relation-deleted": "Relation Deleted",
"action-type-rpc-call": "RPC Call",
"action-type-alarm-ack": "Alarm Ack",
"action-type-alarm-clear": "Alarm Clear",
"action-type-assigned-to-edge": "Assigned to Edge",
"action-type-unassigned-from-edge": "Unassigned from Edge",
"action-type-credentials-request": "Credentials Request",
"action-type-entity-merge-request": "Entity Merge Request"
},
"error": {
"unable-to-connect": "¡No se puede conectar al servidor! Por favor, revise su conexión a Internet.",
"unhandled-error-code": "Código de error no controlado: {{errorCode}}",
@ -1477,7 +1534,11 @@
"unset-auto-assign-to-edge": "No asigne una cadena de reglas a los bordes en la creación",
"unset-auto-assign-to-edge-title": "¿Está seguro de que no desea asignar la cadena de reglas de borde '{{ruleChainName}}' a los bordes en la creación?",
"unset-auto-assign-to-edge-text": "Después de la confirmación, la cadena de reglas de borde ya no se asignará automáticamente a los bordes en la creación.",
"edge-template-root": "Raíz de plantilla"
"edge-template-root": "Raíz de plantilla",
"set-auto-assign-to-edge-card": "Asignar a borde (s) en la creación",
"set-default-root-edge": "Hacer raíz predeterminada de la cadena de reglas",
"set-default-root-edge-rulechain-title": "¿Está seguro de que desea que la cadena de reglas '{{ruleChainName}}' sea la raíz del borde predeterminada?",
"set-default-root-edge-rulechain-text": "Después de la confirmación, la cadena de reglas se convertirá en la raíz del borde predeterminada y manejará todos los mensajes de transporte entrantes."
},
"rulenode": {
"details": "Detalles",

67
ui/src/app/locale/locale.constant-fr_FR.json

@ -830,8 +830,67 @@
"event-action": "Action d'événement",
"load-entity-error": "Entité introuvable. Échec du chargement des informations",
"unassign-edges-text": "Après la confirmation, tous les bordures sélectionnés ne seront plus attribués et ne seront pas accessibles par le client.",
"unassign-edges-title": "Voulez-vous vraiment annuler l'attribution de {count, plural, 1 {1 bordure} other {# bordures}}?"
"unassign-edges-title": "Voulez-vous vraiment annuler l'attribution de {count, plural, 1 {1 bordure} other {# bordures}}?",
"edge-file": "Fichier Edge",
"name-starts-with": "Le nom du bord commence par",
"rulechain-templates": "Modèles de chaîne de règles",
"rulechain-template": "Modèle de chaîne de règles",
"unassign-edges-action-title": "Annuler l'attribution de {count, plural, 1 {1 edge} other {# bords}} au client",
"enter-edge-type": "Entrez le type d'arête",
"no-edge-types-matching": "Aucun type d'arête correspondant à '{{entitySubtype}}' n'a été trouvé.",
"edge-type-list-empty": "Aucun type d'arête sélectionné.",
"edge-types": "Types de bords",
"license-key-hint": "Pour obtenir votre licence, accédez à la <a href='https://thingsboard.io/pricing/?active=thingsboard-edge' target='_blank'> page de tarification </a> et sélectionnez la meilleure option de licence pour votre Cas.",
"cloud-endpoint-hint": "Edge nécessite un accès HTTP (s) au Cloud (ThingsBoard CE / PE) pour vérifier la clé de licence. Veuillez spécifier l'URL cloud à laquelle Edge peut se connecter.",
"missing-related-rule-chains-title": "Edge n'a pas de chaîne (s) de règles associées",
"missing-related-rule-chains-text": "Les chaînes de règles affectées aux tronçons utilisent des nœuds de règles qui transfèrent les messages aux chaînes de règles non affectées à ce tronçon. <br> <br> Liste des chaînes de règles manquantes: <br> {{missingRuleChains}}",
"downlinks": "Liens descendants",
"no-downlinks-prompt": "Aucun lien descendant trouvé",
"assigned-to-customer-widget": "Attribué à: {{customerTitle}}",
"widget-datasource-error": "Ce widget prend en charge uniquement la source de données d'entité EDGE"
},
"edge-event": {
"type-dashboard": "Dashboard",
"type-asset": "Asset",
"type-device": "Device",
"type-device-profile": "Device Profile",
"type-entity-view": "Entity View",
"type-alarm": "Alar",
"type-rule-chain": "Rule Chain",
"type-rule-chain-metadata": "Rule Chain Metadata",
"type-edge": "Edge",
"type-entity-group": "Entity Group",
"type-scheduler-event": "Scheduler Event",
"type-white-labeling": "White Labeling",
"type-login-white-labeling": "White Labeling Login",
"type-user": "User",
"type-tenant": "Tenant",
"type-customer": "Customer",
"type-custom-translation": "Custom Translation",
"type-relation": "Relation",
"type-widgets-bundle": "Widgets Bundle",
"type-widgets-type": "Widgets Type",
"type-admin-settings": "Admin Settings",
"action-type-added": "Added",
"action-type-deleted": "Deleted",
"action-type-updated": "Updated",
"action-type-post-attributes": "Post Attributes",
"action-type-attributes-updated": "Attributes Updated",
"action-type-attributes-deleted": "Attributes Deleted",
"action-type-timeseries-updated": "Timeseries Updated",
"action-type-credentials-updated": "Credentials Updated",
"action-type-assigned-to-customer": "Assigned to Customer",
"action-type-unassigned-from-customer": "Unassigned from Customer",
"action-type-relation-add-or-update": "Relation Add or Update",
"action-type-relation-deleted": "Relation Deleted",
"action-type-rpc-call": "RPC Call",
"action-type-alarm-ack": "Alarm Ack",
"action-type-alarm-clear": "Alarm Clear",
"action-type-assigned-to-edge": "Assigned to Edge",
"action-type-unassigned-from-edge": "Unassigned from Edge",
"action-type-credentials-request": "Credentials Request",
"action-type-entity-merge-request": "Entity Merge Request"
},
"entity": {
"add-alias": "Ajouter un alias d'entité",
"alarm-name-starts-with": "Les actifs dont le nom commence par '{{prefix}}'",
@ -1455,7 +1514,11 @@
"unset-auto-assign-to-edge": "N'attribuez pas de chaîne de règles aux arêtes lors de la création",
"unset-auto-assign-to-edge-title": "Êtes-vous sûr de ne pas vouloir attribuer la chaîne de règles d'arête '{{ruleChainName}}' à l'arête (s) lors de la création?",
"unset-auto-assign-to-edge-text": "Après la confirmation, la chaîne de règles d'arêtes ne sera plus automatiquement affectée aux arêtes lors de la création.",
"edge-template-root": "Racine du modèle"
"edge-template-root": "Racine du modèle",
"set-auto-assign-to-edge-card": "Affecter aux arêtes lors de la création",
"set-default-root-edge": "Rendre la chaîne de règles racine par défaut",
"set-default-root-edge-rulechain-title": "Voulez-vous vraiment définir la racine de périphérie par défaut de la chaîne de règles '{{ruleChainName}}'?",
"set-default-root-edge-rulechain-text": "Après la confirmation, la chaîne de règles deviendra la racine périphérique par défaut et gérera tous les messages de transport entrants."
},
"rulenode": {
"add": "Ajouter un noeud de règle",

9
ui/src/app/rulechain/rulechain-fieldset.tpl.html

@ -24,8 +24,11 @@
class="md-raised md-primary">{{ 'rulechain.delete' | translate }}</md-button>
</div>
<div layout="row"><md-button ng-click="onSetRootRuleChain({event: $event})"
ng-show="!isEdit && !ruleChain.root && ruleChainsScope == 'tenant'"
ng-show="!isEdit && ((!ruleChain.root && ruleChainsScope == 'tenant') || (ruleChainsScope == 'edge' && edge.rootRuleChainId.id !== ruleChain.id.id))"
class="md-raised md-primary">{{ 'rulechain.set-root' | translate }}</md-button>
<md-button ng-click="onUnassignFromEdge({event: $event})"
ng-show="!isEdit && ruleChainsScope == 'edge' && edge.rootRuleChainId.id !== ruleChain.id.id"
class="md-raised md-primary">{{ 'edge.unassign-from-edge' | translate }}</md-button>
<md-button ng-click="onSetRootRuleChain({event: $event})"
ng-show="!isEdit && !ruleChain.root && ruleChainsScope == 'edges'"
class="md-raised md-primary">{{ 'rulechain.set-edge-template-root-rulechain' | translate }}</md-button>
@ -36,9 +39,7 @@
ng-show="!isEdit && !ruleChain.root && ruleChain.isDefault && ruleChainsScope == 'edges'"
class="md-raised md-primary">{{ 'rulechain.unset-auto-assign-to-edge' | translate }}</md-button>
<md-button ng-click="onSetRootRuleChain({event: $event})"
ng-show="!isEdit && ruleChainsScope == 'edge' && edge.rootRuleChainId.id !== ruleChain.id.id"
class="md-raised md-primary">{{ 'rulechain.set-root' | translate }}</md-button>
</div>
<div layout="row">
<md-button ngclipboard data-clipboard-action="copy"

2
ui/src/app/rulechain/rulechain.controller.js

@ -1272,7 +1272,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
if (vm.ruleChain.type === vm.types.ruleChainType.core) {
$state.go('home.ruleChains.ruleChain', {ruleChainId: vm.ruleChain.id.id});
} else {
$state.go('home.edges.edgeRuleChains.ruleChain', {ruleChainId: vm.ruleChain.id.id});
$state.go('home.edges.ruleChains.ruleChain', {ruleChainId: vm.ruleChain.id.id});
}
});
} else {

1
ui/src/app/rulechain/rulechain.directive.js

@ -44,6 +44,7 @@ export default function RuleChainDirective($compile, $templateCache, $mdDialog,
edge: '=',
onSetAutoAssignToEdgeRuleChain: '&',
onUnsetAutoAssignToEdgeRuleChain: '&',
onUnassignFromEdge: '&',
onSetRootRuleChain: '&',
onExportRuleChain: '&',
onDeleteRuleChain: '&'

6
ui/src/app/rulechain/rulechain.routes.js

@ -125,7 +125,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ncyBreadcrumb: {
label: '{"icon": "settings_ethernet", "label": "{{ (\'rulechain.import\' | translate) + \': \'+ vm.ruleChain.name }}", "translate": "false"}'
}
}).state('home.edges.edgeRuleChains', {
}).state('home.edges.ruleChains', {
url: '/ruleChains',
params: {'topIndex': 0},
module: 'private',
@ -145,7 +145,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ncyBreadcrumb: {
label: '{"icon": "settings_ethernet", "label": "edge.rulechain-templates"}'
}
}).state('home.edges.edgeRuleChains.ruleChain', {
}).state('home.edges.ruleChains.ruleChain', {
url: '/:ruleChainId',
reloadOnSearch: false,
module: 'private',
@ -182,7 +182,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ncyBreadcrumb: {
label: '{"icon": "settings_ethernet", "label": "{{ vm.ruleChain.name }}", "translate": "false"}'
}
}).state('home.edges.edgeRuleChains.importRuleChain', {
}).state('home.edges.ruleChains.importRuleChain', {
url: '/edges/ruleChains/import',
reloadOnSearch: false,
module: 'private',

46
ui/src/app/rulechain/rulechains.controller.js

@ -27,7 +27,6 @@ export default function RuleChainsController(ruleChainService, userService, impo
$document, $q, edgeService) {
var vm = this;
var edgeId = $stateParams.edgeId;
vm.ruleChainsScope = $state.$current.data.ruleChainsType;
@ -53,6 +52,9 @@ export default function RuleChainsController(ruleChainService, userService, impo
var ruleChainGroupActionsList = [];
vm.types = types;
var edgeId = $stateParams.edgeId;
vm.edge = null;
vm.ruleChainGridConfig = {
refreshParamsFunc: null,
@ -99,6 +101,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
vm.setRootRuleChain = setRootRuleChain;
vm.setAutoAssignToEdgeRuleChain = setAutoAssignToEdgeRuleChain;
vm.unsetAutoAssignToEdgeRuleChain = unsetAutoAssignToEdgeRuleChain;
vm.unassignFromEdge = unassignFromEdge;
initController();
@ -247,7 +250,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
onAction: function ($event) {
importExport.importRuleChain($event, types.ruleChainType.edge).then(
function(ruleChainImport) {
$state.go('home.edges.edgeRuleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.ruleChainType.edge});
$state.go('home.edges.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.ruleChainType.edge});
}
);
},
@ -277,7 +280,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
ruleChainActionsList.push(
{
onAction: function ($event, item) {
unassignFromEdge($event, item, edgeId);
unassignFromEdge($event, item);
},
name: function() { return $translate.instant('action.unassign') },
details: function() { return $translate.instant('edge.unassign-from-edge') },
@ -289,7 +292,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
ruleChainGroupActionsList.push(
{
onAction: function ($event, items) {
unassignRuleChainsFromEdge($event, items, edgeId);
unassignRuleChainsFromEdge($event, items);
},
name: function() { return $translate.instant('rulechain.unassign-rulechains') },
details: function(selectedCount) {
@ -351,12 +354,11 @@ export default function RuleChainsController(ruleChainService, userService, impo
return ruleChain;
});
ruleChains.data = data;
deferred.resolve(ruleChains);
}, function fail() {
deferred.reject();
}
)
);
return deferred.promise;
}
@ -365,19 +367,9 @@ export default function RuleChainsController(ruleChainService, userService, impo
return ruleChainService.getRuleChains(pageLink, null, type);
} else if (vm.ruleChainsScope === 'edges') {
var deferred = $q.defer();
ruleChainService.getRuleChains(pageLink, null, type).then(
function success(ruleChains) {
mapRuleChainsWithDefaultEdges(ruleChains).then(
function success(response) {
deferred.resolve(response);
}, function fail() {
deferred.reject();
}
);
}, function fail() {
deferred.reject();
}
);
ruleChainService.getRuleChains(pageLink, null, type)
.then(ruleChains => mapRuleChainsWithDefaultEdges(ruleChains))
.then(ruleChains => deferred.resolve(ruleChains));
return deferred.promise;
}
}
@ -399,9 +391,9 @@ export default function RuleChainsController(ruleChainService, userService, impo
}
var ruleChainParams = {ruleChainId: ruleChain.id.id};
if (vm.ruleChainsScope === 'edge') {
$state.go('home.edges.ruleChains.ruleChain', Object.assign(ruleChainParams, edgeId = vm.edge.id.id));
$state.go('home.edges.ruleChains.ruleChain', ruleChainParams);
} else if (vm.ruleChainsScope === 'edges') {
$state.go('home.edges.edgeRuleChains.ruleChain', ruleChainParams);
$state.go('home.edges.ruleChains.ruleChain', ruleChainParams);
} else {
$state.go('home.ruleChains.ruleChain', ruleChainParams);
}
@ -416,7 +408,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
}
function isRootRuleChain(ruleChain) {
if (angular.isDefined(vm.edge) && vm.edge != null) {
if (vm.edge != null) {
return angular.isDefined(vm.edge.rootRuleChainId) && vm.edge.rootRuleChainId != null && vm.edge.rootRuleChainId.id === ruleChain.id.id;
} else {
return ruleChain && ruleChain.root;
@ -424,7 +416,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
}
function isNonRootRuleChain(ruleChain) {
if (angular.isDefined(vm.edge) && vm.edge != null) {
if (vm.edge != null) {
return angular.isDefined(vm.edge.rootRuleChainId) && vm.edge.rootRuleChainId != null && vm.edge.rootRuleChainId.id !== ruleChain.id.id;
} else {
return ruleChain && !ruleChain.root;
@ -454,7 +446,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
.cancel($translate.instant('action.no'))
.ok($translate.instant('action.yes'));
$mdDialog.show(confirm).then(function () {
if (angular.isDefined(vm.edge) && vm.edge != null) {
if (vm.edge != null) {
edgeService.setRootRuleChain(vm.edge.id.id, ruleChain.id.id).then(
(edge) => {
vm.edge = edge;
@ -525,7 +517,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
});
}
function unassignRuleChainsFromEdge($event, items, edgeId) {
function unassignRuleChainsFromEdge($event, items) {
var confirm = $mdDialog.confirm()
.targetEvent($event)
.title($translate.instant('rulechain.unassign-rulechains-title', {count: items.selectedCount}, 'messageformat'))
@ -567,7 +559,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
controller: 'AddRuleChainsToEdgeController',
controllerAs: 'vm',
templateUrl: addRuleChainsToEdgeTemplate,
locals: {edgeId: edgeId, ruleChains: ruleChains},
locals: {edgeId, ruleChains},
parent: angular.element($document[0].body),
fullscreen: true,
targetEvent: $event
@ -604,7 +596,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
});
}
function unassignFromEdge($event, ruleChain, edgeId) {
function unassignFromEdge($event, ruleChain) {
if ($event) {
$event.stopPropagation();
}

1
ui/src/app/rulechain/rulechains.tpl.html

@ -30,6 +30,7 @@
edge="vm.edge"
on-set-auto-assign-to-edge-rule-chain="vm.setAutoAssignToEdgeRuleChain(event, vm.grid.detailsConfig.currentItem)"
on-unset-auto-assign-to-edge-rule-chain="vm.unsetAutoAssignToEdgeRuleChain(event, vm.grid.detailsConfig.currentItem)"
on-unassign-from-edge="vm.unassignFromEdge(event, vm.grid.detailsConfig.currentItem)"
on-set-root-rule-chain="vm.setRootRuleChain(event, vm.grid.detailsConfig.currentItem)"
on-export-rule-chain="vm.exportRuleChain(event, vm.grid.detailsConfig.currentItem)"
on-delete-rule-chain="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)">

4
ui/src/app/services/menu.service.js

@ -202,7 +202,7 @@ function Menu(userService, $state, $rootScope) {
{
name: 'edge.rulechain-templates',
type: 'link',
state: 'home.edges.edgeRuleChains',
state: 'home.edges.ruleChains',
icon: 'settings_ethernet'
}
]
@ -293,7 +293,7 @@ function Menu(userService, $state, $rootScope) {
{
name: 'edge.rulechain-templates',
icon: 'settings_ethernet',
state: 'home.edges.edgeRuleChains'
state: 'home.edges.ruleChains'
}
]

240
ui/src/app/widget/lib/edges-overview-widget.js

@ -0,0 +1,240 @@
/*
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import './edges-overview-widget.scss';
/* eslint-disable import/no-unresolved, import/default */
import edgesOverviewWidgetTemplate from './edges-overview-widget.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
export default angular.module('thingsboard.widgets.edgesOverviewWidget', [])
.directive('tbEdgesOverviewWidget', EdgesOverviewWidget)
.name;
/* eslint-disable no-unused-vars, no-undef */
/*@ngInject*/
function EdgesOverviewWidget() {
return {
restrict: "E",
scope: true,
bindToController: {
ctx: '='
},
controller: EdgesOverviewWidgetController,
controllerAs: 'vm',
templateUrl: edgesOverviewWidgetTemplate
};
}
/*@ngInject*/
function EdgesOverviewWidgetController($scope, $translate, types, utils, entityService, edgeService, customerService, userService) {
var vm = this;
vm.showData = true;
vm.nodeIdCounter = 0;
vm.entityNodesMap = {};
vm.entityGroupsNodesMap = {};
vm.customerTitle = null;
vm.edgeIsDatasource = true;
var edgeGroupsTypes = [
types.entityType.asset,
types.entityType.device,
types.entityType.entityView,
types.entityType.dashboard,
types.entityType.rulechain
];
vm.onNodeSelected = onNodeSelected;
$scope.$watch('vm.ctx', function() {
if (vm.ctx && vm.ctx.defaultSubscription) {
vm.settings = vm.ctx.settings;
vm.widgetConfig = vm.ctx.widgetConfig;
vm.subscription = vm.ctx.defaultSubscription;
vm.datasources = vm.subscription.datasources;
updateDatasources();
}
});
function onNodeSelected(node, event) {
var nodeId;
if (!node) {
nodeId = -1;
} else {
nodeId = node.id;
}
if (nodeId !== -1) {
var selectedNode = vm.entityNodesMap[nodeId];
if (selectedNode) {
var descriptors = vm.ctx.actionsApi.getActionDescriptors('nodeSelected');
if (descriptors.length) {
var entity = selectedNode.data.nodeCtx.entity;
vm.ctx.actionsApi.handleWidgetAction(event, descriptors[0], entity.id, entity.name, { nodeCtx: selectedNode.data.nodeCtx });
}
}
}
}
function updateDatasources() {
vm.loadNodes = loadNodes;
}
function loadNodes(node, cb) {
var datasource = vm.datasources[0];
if (node.id === '#' && datasource) {
if (datasource.type === types.datasourceType.entity && datasource.entity && datasource.entity.id.entityType === types.entityType.edge) {
var selectedEdge = datasource.entity;
vm.customerTitle = getCustomerTitle(selectedEdge.id.id);
// vm.ctx.widgetTitle = selectedEdge.name;
cb(loadNodesForEdge(selectedEdge.id.id, selectedEdge));
} else if (datasource.type === types.datasourceType.function) {
cb(loadNodesForEdge(null, null));
} else {
vm.edgeIsDatasource = false;
cb([]);
}
} else if (node.data && node.data.entity && node.data.entity.id.entityType === types.entityType.edge) {
var edgeId = node.data.entity.id.id;
var entityType = node.data.entityType;
var pageLink = {limit: 100};
entityService.getAssignedToEdgeEntitiesByType(edgeId, entityType, pageLink).then(
(entities) => {
if (entities.data.length > 0) {
cb(entitiesToNodes(node.id, entities.data));
} else {
cb([]);
}
}
);
} else {
cb([]);
}
}
function entitiesToNodes(parentNodeId, entities) {
var nodes = [];
vm.entityNodesMap[parentNodeId] = {};
if (entities) {
entities.forEach(
(entity) => {
var node = createEntityNode(parentNodeId, entity, entity.id.entityType);
nodes.push(node);
}
);
}
return nodes;
}
function createEntityNode(parentNodeId, entity, entityType) {
var nodesMap = vm.entityNodesMap[parentNodeId];
if (!nodesMap) {
nodesMap = {};
vm.entityNodesMap[parentNodeId] = nodesMap;
}
var node = {
id: ++vm.nodeIdCounter,
icon: 'material-icons ' + iconForGroupType(entityType),
text: entity.name,
children: false,
data: {
entity,
internalId: entity.id.id
}
};
nodesMap[entity.id.id] = node.id;
return node;
}
function loadNodesForEdge(parentNodeId, entity) {
var nodes = [];
vm.entityGroupsNodesMap[parentNodeId] = {};
var allowedGroupTypes = edgeGroupsTypes;
if (userService.getAuthority() === 'CUSTOMER_USER') {
allowedGroupTypes = edgeGroupsTypes.filter(type => type !== types.entityType.rulechain);
}
allowedGroupTypes.forEach(
(entityType) => {
var node = {
id: ++vm.nodeIdCounter,
icon: 'material-icons ' + iconForGroupType(entityType),
text: textForGroupType(entityType),
children: true,
data: {
entityType,
entity,
internalId: entity ? entity.id.id + '_' + entityType : utils.guid()
}
};
nodes.push(node);
}
)
return nodes;
}
function iconForGroupType(entityType) {
switch (entityType) {
case types.entityType.asset:
return 'tb-asset-group';
case types.entityType.device:
return 'tb-device-group';
case types.entityType.entityView:
return 'tb-entity-view-group';
case types.entityType.dashboard:
return 'tb-dashboard-group';
case types.entityType.rulechain:
return 'tb-rule-chain-group';
}
return '';
}
function textForGroupType(entityType) {
switch (entityType) {
case types.entityType.asset:
return $translate.instant('asset.assets');
case types.entityType.device:
return $translate.instant('device.devices');
case types.entityType.entityView:
return $translate.instant('entity-view.entity-views');
case types.entityType.rulechain:
return $translate.instant('rulechain.rulechains');
case types.entityType.dashboard:
return $translate.instant('dashboard.dashboards');
}
return '';
}
function getCustomerTitle(edgeId) {
edgeService.getEdge(edgeId, true).then(
function success(edge) {
if (edge.customerId.id !== types.id.nullUid) {
customerService.getCustomer(edge.customerId.id, { ignoreErrors: true }).then(
function success(customer) {
vm.customerTitle = $translate.instant('edge.assigned-to-customer-widget', { customerTitle: customer.title });
},
function fail() {
}
);
}
},
function fail() {
}
)
}
}

60
ui/src/app/widget/lib/edges-overview-widget.scss

@ -0,0 +1,60 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.tb-edges-overview {
.mat-subheader {
padding: 15px;
font-size: 14px;
font-weight: 400;
opacity: .5;
}
.tb-entities-nav-tree-panel {
overflow-x: auto;
overflow-y: auto;
}
}
@media (max-width: 768px) {
.tb-edges-overview {
.tb-entities-nav-tree-panel {
.tb-nav-tree-container {
&.jstree-proton-responsive {
.jstree-anchor {
div.node-icon {
width: 40px;
height: 40px;
margin: 0;
background-size: 24px 24px;
}
md-icon.node-icon {
width: 40px;
min-width: 40px;
height: 40px;
min-height: 40px;
margin: 0;
&.material-icons { /* stylelint-disable-line selector-max-class */
font-size: 24px;
line-height: 40px;
}
}
}
}
}
}
}
}

29
ui/src/app/widget/lib/edges-overview-widget.tpl.html

@ -0,0 +1,29 @@
<!--
Copyright © 2016-2020 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div class="tb-absolute-fill tb-edges-overview" layout="column">
<div ng-show="vm.showData" flex class="tb-absolute-fill" layout="column">
<span class="mat-subheader" ng-if="vm.customerTitle">{{ vm.customerTitle }}</span>
<span class="mat-subheader" ng-if="!vm.edgeIsDatasource" translate>edge.widget-datasource-error</span>
<div flex class="tb-entities-nav-tree-panel">
<tb-nav-tree
on-node-selected="vm.onNodeSelected(node, event)"
load-nodes="vm.loadNodes"
></tb-nav-tree>
</div>
</div>
</div>
Loading…
Cancel
Save