diff --git a/application/src/main/data/upgrade/2.4.x/schema_update.cql b/application/src/main/data/upgrade/2.4.x/schema_update.cql index 3b25daa2fd..b518c7e68a 100644 --- a/application/src/main/data/upgrade/2.4.x/schema_update.cql +++ b/application/src/main/data/upgrade/2.4.x/schema_update.cql @@ -17,16 +17,45 @@ CREATE TABLE IF NOT EXISTS thingsboard.edge ( id timeuuid, tenant_id timeuuid, + customer_id timeuuid, name text, search_text text, configuration text, additional_info text, PRIMARY KEY (id, tenant_id) -); + ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_name AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, name, id, customer_id, type) + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_search_text AS SELECT * from thingsboard.edge - WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id ) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); \ No newline at end of file + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_by_type_and_search_text AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id) + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_customer_and_search_text AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_customer_by_type_and_search_text AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); \ No newline at end of file diff --git a/application/src/main/data/upgrade/2.4.x/schema_update.sql b/application/src/main/data/upgrade/2.4.x/schema_update.sql index 7fe32deb9a..c080457d70 100644 --- a/application/src/main/data/upgrade/2.4.x/schema_update.sql +++ b/application/src/main/data/upgrade/2.4.x/schema_update.sql @@ -17,8 +17,16 @@ CREATE TABLE IF NOT EXISTS edge ( id varchar(31) NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, additional_info varchar, + customer_id varchar(31), configuration varchar(10000000), name varchar(255), search_text varchar(255), tenant_id varchar(31) -); \ No newline at end of file +); + +ALTER TABLE asset ADD edge_id varchar(31); +ALTER TABLE device ADD edge_id varchar(31); +ALTER TABLE entity_view ADD edge_id varchar(31); + +ALTER TABLE dashboard ADD assigned_edges varchar(1000000); +ALTER TABLE rule_chain ADD assigned_edges varchar(1000000); \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java index 2bd11cdac6..3ad3a85e78 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java @@ -53,6 +53,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo implements H public Edge(Edge edge) { super(edge); this.tenantId = edge.getTenantId(); + this.customerId = edge.getCustomerId(); this.name = edge.getName(); this.configuration = edge.getConfiguration(); this.additionalInfo = edge.getAdditionalInfo(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 987d0e69dd..3705a6c276 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -352,6 +352,7 @@ public class ModelConstants { */ public static final String EDGE_COLUMN_FAMILY_NAME = "edge"; public static final String EDGE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; + public static final String EDGE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; public static final String EDGE_NAME_PROPERTY = "name"; public static final String EDGE_CONFIGURATION_PROPERTY = "configuration"; public static final String EDGE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java index 1196d14314..0f82323237 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java @@ -23,6 +23,7 @@ import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.databind.JsonNode; import lombok.Data; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.SearchTextEntity; @@ -33,6 +34,7 @@ import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ADDITIONAL_INFO_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; @@ -50,6 +52,10 @@ public class EdgeEntity implements SearchTextEntity { @Column(name = EDGE_TENANT_ID_PROPERTY) private UUID tenantId; + @ClusteringColumn + @Column(name = EDGE_CUSTOMER_ID_PROPERTY) + private UUID customerId; + @Column(name = EDGE_NAME_PROPERTY) private String name; @@ -90,6 +96,9 @@ public class EdgeEntity implements SearchTextEntity { if (tenantId != null) { edge.setTenantId(new TenantId(tenantId)); } + if (customerId != null) { + edge.setCustomerId(new CustomerId(customerId)); + } edge.setName(name); edge.setConfiguration(configuration); edge.setAdditionalInfo(additionalInfo); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java index f70028e5da..d06e35f1a2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java @@ -23,6 +23,7 @@ import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -34,7 +35,9 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; +import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; @@ -49,6 +52,9 @@ public class EdgeEntity extends BaseSqlEntity implements SearchTextEntity< @Column(name = EDGE_TENANT_ID_PROPERTY) private String tenantId; + @Column(name = EDGE_CUSTOMER_ID_PROPERTY) + private String customerId; + @Column(name = EDGE_NAME_PROPERTY) private String name; @@ -100,6 +106,9 @@ public class EdgeEntity extends BaseSqlEntity implements SearchTextEntity< if (tenantId != null) { edge.setTenantId(new TenantId(UUIDConverter.fromString(tenantId))); } + if (customerId != null) { + edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId))); + } edge.setName(name); edge.setConfiguration(configuration); edge.setAdditionalInfo(additionalInfo); diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql index 58654504dd..afc9f96877 100644 --- a/dao/src/main/resources/cassandra/schema-entities.cql +++ b/dao/src/main/resources/cassandra/schema-entities.cql @@ -716,6 +716,7 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_ent CREATE TABLE IF NOT EXISTS thingsboard.edge ( id timeuuid, tenant_id timeuuid, + customer_id timeuuid, name text, search_text text, configuration text, @@ -723,9 +724,37 @@ CREATE TABLE IF NOT EXISTS thingsboard.edge ( PRIMARY KEY (id, tenant_id) ); +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_name AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, name, id, customer_id, type) + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); + CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_search_text AS SELECT * from thingsboard.edge - WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id ) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); \ No newline at end of file + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_by_type_and_search_text AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id) + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_customer_and_search_text AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_customer_by_type_and_search_text AS + SELECT * + from thingsboard.edge + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); \ No newline at end of file diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index c95c2f1036..a1b0889932 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -41,6 +41,7 @@ CREATE TABLE IF NOT EXISTS asset ( id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, additional_info varchar, customer_id varchar(31), + edge_id varchar(31), name varchar(255), search_text varchar(255), tenant_id varchar(31), @@ -106,6 +107,7 @@ CREATE TABLE IF NOT EXISTS dashboard ( id varchar(31) NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, configuration varchar(10000000), assigned_customers varchar(1000000), + assigned_edges varchar(1000000), search_text varchar(255), tenant_id varchar(31), title varchar(255) @@ -115,6 +117,7 @@ CREATE TABLE IF NOT EXISTS device ( id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY, additional_info varchar, customer_id varchar(31), + edge_id varchar(31), type varchar(255), name varchar(255), label varchar(255), @@ -215,7 +218,8 @@ CREATE TABLE IF NOT EXISTS rule_chain ( root boolean, debug_mode boolean, search_text varchar(255), - tenant_id varchar(31) + tenant_id varchar(31), + assigned_edges varchar(1000000) ); CREATE TABLE IF NOT EXISTS rule_node ( @@ -235,6 +239,7 @@ CREATE TABLE IF NOT EXISTS entity_view ( entity_type varchar(255), tenant_id varchar(31), customer_id varchar(31), + edge_id varchar(31), type varchar(255), name varchar(255), keys varchar(10000000), @@ -247,6 +252,7 @@ CREATE TABLE IF NOT EXISTS entity_view ( CREATE TABLE IF NOT EXISTS edge ( id varchar(31) NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, additional_info varchar, + customer_id varchar(31), configuration varchar(10000000), name varchar(255), search_text varchar(255), diff --git a/ui/src/app/edge/add-edges-to-customer.controller.js b/ui/src/app/edge/add-edges-to-customer.controller.js new file mode 100644 index 0000000000..299d5278c2 --- /dev/null +++ b/ui/src/app/edge/add-edges-to-customer.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 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. + */ +/*@ngInject*/ +export default function AddEdgesToCustomerController(edgeService, $mdDialog, $q, customerId, edges) { + + var vm = this; + + vm.edges = edges; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.hasData = hasData; + vm.noData = noData; + vm.searchEdgeTextUpdated = searchEdgeTextUpdated; + vm.toggleEdgeSelection = toggleEdgeSelection; + + vm.theEdges = { + getItemAtIndex: function (index) { + if (index > vm.edges.data.length) { + vm.theEdges.fetchMoreItems_(index); + return null; + } + var item = vm.edges.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.edges.hasNext) { + return vm.edges.data.length + vm.edges.nextPageLink.limit; + } else { + return vm.edges.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.edges.hasNext && !vm.edges.pending) { + vm.edges.pending = true; + edgeService.getTenantEdges(vm.edges.nextPageLink, false).then( + function success(edges) { + vm.edges.data = vm.edges.data.concat(edges.data); + vm.edges.nextPageLink = edges.nextPageLink; + vm.edges.hasNext = edges.hasNext; + if (vm.edges.hasNext) { + vm.edges.nextPageLink.limit = vm.edges.pageSize; + } + vm.edges.pending = false; + }, + function fail() { + vm.edges.hasNext = false; + vm.edges.pending = false; + }); + } + } + }; + + function cancel () { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var edgeId in vm.edges.selections) { + tasks.push(edgeService.assignEdgeToCustomer(customerId, edgeId)); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData() { + return vm.edges.data.length == 0 && !vm.edges.hasNext; + } + + function hasData() { + return vm.edges.data.length > 0; + } + + function toggleEdgeSelection($event, edge) { + $event.stopPropagation(); + var selected = angular.isDefined(edge.selected) && edge.selected; + edge.selected = !selected; + if (edge.selected) { + vm.edges.selections[edge.id.id] = true; + vm.edges.selectedCount++; + } else { + delete vm.edges.selections[edge.id.id]; + vm.edges.selectedCount--; + } + } + + function searchEdgeTextUpdated() { + vm.edges = { + pageSize: vm.edges.pageSize, + data: [], + nextPageLink: { + limit: vm.edges.pageSize, + textSearch: vm.searchText + }, + selections: {}, + selectedCount: 0, + hasNext: true, + pending: false + }; + } + +} diff --git a/ui/src/app/edge/add-edges-to-customer.tpl.html b/ui/src/app/edge/add-edges-to-customer.tpl.html new file mode 100644 index 0000000000..42fc2e6b3d --- /dev/null +++ b/ui/src/app/edge/add-edges-to-customer.tpl.html @@ -0,0 +1,77 @@ + + +
+ +
+

edge.assign-edge-to-customer

+ + + + +
+
+ + + +
+
+ edge.assign-edge-to-customer-text + + + + search + + + +
+ edge.no-edges-text + + + + + {{ edge.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/edge/assign-to-customer.controller.js b/ui/src/app/edge/assign-to-customer.controller.js new file mode 100644 index 0000000000..72d989404b --- /dev/null +++ b/ui/src/app/edge/assign-to-customer.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 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. + */ +/*@ngInject*/ +export default function AssignEdgeToCustomerController(customerService, edgeService, $mdDialog, $q, edgeIds, customers) { + + var vm = this; + + vm.customers = customers; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.isCustomerSelected = isCustomerSelected; + vm.hasData = hasData; + vm.noData = noData; + vm.searchCustomerTextUpdated = searchCustomerTextUpdated; + vm.toggleCustomerSelection = toggleCustomerSelection; + + vm.theCustomers = { + getItemAtIndex: function (index) { + if (index > vm.customers.data.length) { + vm.theCustomers.fetchMoreItems_(index); + return null; + } + var item = vm.customers.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.customers.hasNext) { + return vm.customers.data.length + vm.customers.nextPageLink.limit; + } else { + return vm.customers.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.customers.hasNext && !vm.customers.pending) { + vm.customers.pending = true; + customerService.getCustomers(vm.customers.nextPageLink).then( + function success(customers) { + vm.customers.data = vm.customers.data.concat(customers.data); + vm.customers.nextPageLink = customers.nextPageLink; + vm.customers.hasNext = customers.hasNext; + if (vm.customers.hasNext) { + vm.customers.nextPageLink.limit = vm.customers.pageSize; + } + vm.customers.pending = false; + }, + function fail() { + vm.customers.hasNext = false; + vm.customers.pending = false; + }); + } + } + }; + + function cancel() { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var i=0;i 0; + } + + function toggleCustomerSelection($event, customer) { + $event.stopPropagation(); + if (vm.isCustomerSelected(customer)) { + vm.customers.selection = null; + } else { + vm.customers.selection = customer; + } + } + + function isCustomerSelected(customer) { + return vm.customers.selection != null && customer && + customer.id.id === vm.customers.selection.id.id; + } + + function searchCustomerTextUpdated() { + vm.customers = { + pageSize: vm.customers.pageSize, + data: [], + nextPageLink: { + limit: vm.customers.pageSize, + textSearch: vm.searchText + }, + selection: null, + hasNext: true, + pending: false + }; + } +} diff --git a/ui/src/app/edge/assign-to-customer.tpl.html b/ui/src/app/edge/assign-to-customer.tpl.html new file mode 100644 index 0000000000..d76ec5ebf4 --- /dev/null +++ b/ui/src/app/edge/assign-to-customer.tpl.html @@ -0,0 +1,76 @@ + + +
+ +
+

edge.assign-edge-to-customer

+ + + + +
+
+ + + +
+
+ edge.assign-to-customer-text + + + + search + + + +
+ customer.no-customers-text + + + + + {{ customer.title }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/edge/edge.controller.js b/ui/src/app/edge/edge.controller.js index efd999c7ae..e157f9539b 100644 --- a/ui/src/app/edge/edge.controller.js +++ b/ui/src/app/edge/edge.controller.js @@ -17,6 +17,8 @@ import addEdgeTemplate from './add-edge.tpl.html'; import edgeCard from './edge-card.tpl.html'; +import assignToCustomerTemplate from './assign-to-customer.tpl.html'; +import addEdgesToCustomerTemplate from './add-edges-to-customer.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ @@ -26,25 +28,62 @@ export function EdgeCardController(types) { var vm = this; vm.types = types; + + vm.isAssignedToCustomer = function() { + if (vm.item && vm.item.customerId && vm.parentCtl.edgesScope === 'tenant' && + vm.item.customerId.id != vm.types.id.nullUid && !vm.item.assignedCustomer.isPublic) { + return true; + } + return false; + } + + vm.isPublic = function() { + if (vm.item && vm.item.assignedCustomer && vm.parentCtl.edgesScope === 'tenant' && vm.item.assignedCustomer.isPublic) { + return true; + } + return false; + } } /*@ngInject*/ -export function EdgeController($rootScope, userService, edgeService, $state, $stateParams, - $document, $mdDialog, $q, $translate, types, securityTypes, userPermissionsService) { +export function EdgeController($rootScope, userService, edgeService, customerService, $state, $stateParams, + $document, $mdDialog, $q, $translate, types, importExport) { + + var customerId = $stateParams.customerId; var edgeActionsList = []; var edgeGroupActionsList = []; + var edgeAddItemActionsList = [ + { + onAction: function ($event) { + vm.grid.addItem($event); + }, + name: function() { return $translate.instant('action.add') }, + details: function() { return $translate.instant('edge.add-edge-text') }, + icon: "insert_drive_file" + }, + { + onAction: function ($event) { + importExport.importEntities($event, types.entityType.edge).then( + function() { + vm.grid.refreshList(); + } + ); + }, + name: function() { return $translate.instant('action.import') }, + details: function() { return $translate.instant('edge.import') }, + icon: "file_upload" + } + ]; + var vm = this; vm.types = types; vm.edgeGridConfig = { - - resource: securityTypes.resource.edge, - deleteItemTitleFunc: deleteEdgeTitle, deleteItemContentFunc: deleteEdgeText, deleteItemsTitleFunc: deleteEdgesTitle, @@ -61,6 +100,7 @@ export function EdgeController($rootScope, userService, edgeService, $state, $st actionsList: edgeActionsList, groupActionsList: edgeGroupActionsList, + addItemActions: edgeAddItemActionsList, onGridInited: gridInited, @@ -68,7 +108,11 @@ export function EdgeController($rootScope, userService, edgeService, $state, $st addItemText: function() { return $translate.instant('edge.add-edge-text') }, noItemsText: function() { return $translate.instant('edge.no-edges-text') }, - itemDetailsText: function() { return $translate.instant('edge.edge-details') } + itemDetailsText: function() { return $translate.instant('edge.edge-details') }, + isDetailsReadOnly: isCustomerUser, + isSelectionEnabled: function () { + return !isCustomerUser(); + } }; if (angular.isDefined($stateParams.items) && $stateParams.items !== null) { @@ -79,43 +123,205 @@ export function EdgeController($rootScope, userService, edgeService, $state, $st vm.edgeGridConfig.topIndex = $stateParams.topIndex; } + vm.edgesScope = $state.$current.data.edgesType; + + vm.assignToCustomer = assignToCustomer; + vm.makePublic = makePublic; + vm.unassignFromCustomer = unassignFromCustomer; + initController(); function initController() { - var fetchEdgesFunction = function (pageLink, edgeType) { - return edgeService.getEdges(pageLink, true, edgeType); - }; - var deleteEdgeFunction = function (edgeId) { - return edgeService.deleteEdge(edgeId); - }; - var refreshEdgesParamsFunction = function() { - return {"topIndex": vm.topIndex}; - }; - - edgeActionsList.push( - { + var fetchEdgesFunction = null; + var deleteEdgeFunction = null; + var refreshEdgesParamsFunction = null; + + var user = userService.getCurrentUser(); + + if (user.authority === 'CUSTOMER_USER') { + vm.edgesScope = 'customer_user'; + customerId = user.customerId; + } + if (customerId) { + vm.customerEdgesTitle = $translate.instant('customer.edges'); + customerService.getShortCustomerInfo(customerId).then( + function success(info) { + if (info.isPublic) { + vm.customerEdgesTitle = $translate.instant('customer.public-edges'); + } + } + ); + } + + if (vm.edgesScope === 'tenant') { + fetchEdgesFunction = function (pageLink, edgeType) { + return edgeService.getTenantEdges(pageLink, true, null, edgeType); + }; + deleteEdgeFunction = function (edgeId) { + return edgeService.deleteEdge(edgeId); + }; + refreshEdgesParamsFunction = function() { + return {"topIndex": vm.topIndex}; + }; + + edgeActionsList.push({ onAction: function ($event, item) { - vm.grid.deleteItem($event, item); + makePublic($event, item); }, - name: function() { return $translate.instant('action.delete') }, - details: function() { return $translate.instant('edge.delete') }, - icon: "delete", - isEnabled: function() { - return userPermissionsService.hasGenericPermission(securityTypes.resource.edge, securityTypes.operation.delete); + name: function() { return $translate.instant('action.share') }, + details: function() { return $translate.instant('edge.make-public') }, + icon: "share", + isEnabled: function(edge) { + return edge && (!edge.customerId || edge.customerId.id === types.id.nullUid); } - } - ); + }); + + edgeActionsList.push( + { + onAction: function ($event, item) { + assignToCustomer($event, [ item.id.id ]); + }, + name: function() { return $translate.instant('action.assign') }, + details: function() { return $translate.instant('edge.assign-to-customer') }, + icon: "assignment_ind", + isEnabled: function(edge) { + return edge && (!edge.customerId || edge.customerId.id === types.id.nullUid); + } + } + ); + + edgeActionsList.push( + { + onAction: function ($event, item) { + unassignFromCustomer($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('edge.unassign-from-customer') }, + icon: "assignment_return", + isEnabled: function(edge) { + return edge && edge.customerId && edge.customerId.id !== types.id.nullUid && !edge.assignedCustomer.isPublic; + } + } + ); - edgeGroupActionsList.push( - { - onAction: function ($event) { - vm.grid.deleteItems($event); + edgeActionsList.push({ + onAction: function ($event, item) { + unassignFromCustomer($event, item, true); }, - name: function() { return $translate.instant('edge.delete-edges') }, - details: deleteEdgesActionTitle, - icon: "delete" + name: function() { return $translate.instant('action.make-private') }, + details: function() { return $translate.instant('edge.make-private') }, + icon: "reply", + isEnabled: function(edge) { + return edge && edge.customerId && edge.customerId.id !== types.id.nullUid && edge.assignedCustomer.isPublic; + } + }); + + edgeActionsList.push( + { + onAction: function ($event, item) { + vm.grid.deleteItem($event, item); + }, + name: function() { return $translate.instant('action.delete') }, + details: function() { return $translate.instant('edge.delete') }, + icon: "delete" + } + ); + + edgeGroupActionsList.push( + { + onAction: function ($event, items) { + assignEdgesToCustomer($event, items); + }, + name: function() { return $translate.instant('edge.assign-edges') }, + details: function(selectedCount) { + return $translate.instant('edge.assign-edges-text', {count: selectedCount}, "messageformat"); + }, + icon: "assignment_ind" + } + ); + + edgeGroupActionsList.push( + { + onAction: function ($event) { + vm.grid.deleteItems($event); + }, + name: function() { return $translate.instant('edge.delete-edges') }, + details: deleteEdgesActionTitle, + icon: "delete" + } + ); + + + + } else if (vm.edgesScope === 'customer' || vm.edgesScope === 'customer_user') { + fetchEdgesFunction = function (pageLink, edgeType) { + return edgeService.getCustomerEdges(customerId, pageLink, true, null, edgeType); + }; + deleteEdgeFunction = function (edgeId) { + return edgeService.unassignEdgeFromCustomer(edgeId); + }; + refreshEdgesParamsFunction = function () { + return {"customerId": customerId, "topIndex": vm.topIndex}; + }; + + if (vm.edgesScope === 'customer') { + edgeActionsList.push( + { + onAction: function ($event, item) { + unassignFromCustomer($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('edge.unassign-from-customer') }, + icon: "assignment_return", + isEnabled: function(edge) { + return edge && !edge.assignedCustomer.isPublic; + } + } + ); + edgeActionsList.push( + { + onAction: function ($event, item) { + unassignFromCustomer($event, item, true); + }, + name: function() { return $translate.instant('action.make-private') }, + details: function() { return $translate.instant('edge.make-private') }, + icon: "reply", + isEnabled: function(edge) { + return edge && edge.assignedCustomer.isPublic; + } + } + ); + + edgeGroupActionsList.push( + { + onAction: function ($event, items) { + unassignEdgesFromCustomer($event, items); + }, + name: function() { return $translate.instant('edge.unassign-edges') }, + details: function(selectedCount) { + return $translate.instant('edge.unassign-edges-action-title', {count: selectedCount}, "messageformat"); + }, + icon: "assignment_return" + } + ); + + vm.edgeGridConfig.addItemAction = { + onAction: function ($event) { + addEdgesToCustomer($event); + }, + name: function() { return $translate.instant('edge.assign-edges') }, + details: function() { return $translate.instant('edge.assign-new-edge') }, + icon: "add" + }; + + + } else if (vm.edgesScope === 'customer_user') { + vm.edgeGridConfig.addItemAction = {}; } - ); + vm.edgeGridConfig.addItemActions = []; + + } + vm.edgeGridConfig.refreshParamsFunc = refreshEdgesParamsFunction; vm.edgeGridConfig.fetchItemsFunc = fetchEdgesFunction; vm.edgeGridConfig.deleteItemFunc = deleteEdgeFunction; @@ -155,7 +361,19 @@ export function EdgeController($rootScope, userService, edgeService, $state, $st edgeService.saveEdge(edge).then( function success(savedEdge) { $rootScope.$broadcast('edgeSaved'); - deferred.resolve(savedEdge); + var edges = [ savedEdge ]; + customerService.applyAssignedCustomersInfo(edges).then( + function success(items) { + if (items && items.length == 1) { + deferred.resolve(items[0]); + } else { + deferred.reject(); + } + }, + function fail() { + deferred.reject(); + } + ); }, function fail() { deferred.reject(); @@ -163,4 +381,154 @@ export function EdgeController($rootScope, userService, edgeService, $state, $st ); return deferred.promise; } + + function isCustomerUser() { + return vm.edgesScope === 'customer_user'; + } + + function assignToCustomer($event, edgeIds) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + customerService.getCustomers({limit: pageSize, textSearch: ''}).then( + function success(_customers) { + var customers = { + pageSize: pageSize, + data: _customers.data, + nextPageLink: _customers.nextPageLink, + selection: null, + hasNext: _customers.hasNext, + pending: false + }; + if (customers.hasNext) { + customers.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AssignEdgeToCustomerController', + controllerAs: 'vm', + templateUrl: assignToCustomerTemplate, + locals: {edgeIds: edgeIds, customers: customers}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function addEdgesToCustomer($event) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + edgeService.getTenantEdges({limit: pageSize, textSearch: ''}, false).then( + function success(_edges) { + var edges = { + pageSize: pageSize, + data: _edges.data, + nextPageLink: _edges.nextPageLink, + selections: {}, + selectedCount: 0, + hasNext: _edges.hasNext, + pending: false + }; + if (edges.hasNext) { + edges.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AddEdgesToCustomerController', + controllerAs: 'vm', + templateUrl: addEdgesToCustomerTemplate, + locals: {customerId: customerId, edges: edges}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function assignEdgesToCustomer($event, items) { + var edgeIds = []; + for (var id in items.selections) { + edgeIds.push(id); + } + assignToCustomer($event, edgeIds); + } + + function unassignFromCustomer($event, edge, isPublic) { + if ($event) { + $event.stopPropagation(); + } + var title; + var content; + var label; + if (isPublic) { + title = $translate.instant('edge.make-private-edge-title', {edgeName: edge.name}); + content = $translate.instant('edge.make-private-edge-text'); + label = $translate.instant('edge.make-private'); + } else { + title = $translate.instant('edge.unassign-edge-title', {edgeName: edge.name}); + content = $translate.instant('edge.unassign-edge-text'); + label = $translate.instant('edge.unassign-edge'); + } + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title(title) + .htmlContent(content) + .ariaLabel(label) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + edgeService.unassignEdgeFromCustomer(edge.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } + + function unassignEdgesFromCustomer($event, items) { + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title($translate.instant('edge.unassign-edges-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('edge.unassign-edges-text')) + .ariaLabel($translate.instant('edge.unassign-edge')) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + var tasks = []; + for (var id in items.selections) { + tasks.push(edgeService.unassignEdgeFromCustomer(id)); + } + $q.all(tasks).then(function () { + vm.grid.refreshList(); + }); + }); + } + + function makePublic($event, edge) { + if ($event) { + $event.stopPropagation(); + } + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title($translate.instant('edge.make-public-edge-title', {edgeName: edge.name})) + .htmlContent($translate.instant('edge.make-public-edge-text')) + .ariaLabel($translate.instant('edge.make-public')) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + edgeService.makeEdgePublic(edge.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } }