16 changed files with 1590 additions and 1 deletions
@ -0,0 +1,237 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2018 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 thingsboardTypes from '../common/types.constant'; |
||||
|
|
||||
|
export default angular.module('thingsboard.api.entityView', [thingsboardTypes]) |
||||
|
.factory('entityViewService', EntityViewService) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function EntityViewService($http, $q, $window, userService, attributeService, customerService, types) { |
||||
|
|
||||
|
var service = { |
||||
|
assignEntityViewToCustomer: assignEntityViewToCustomer, |
||||
|
deleteEntityView: deleteEntityView, |
||||
|
getCustomerEntityViews: getCustomerEntityViews, |
||||
|
getEntityView: getEntityView, |
||||
|
getEntityViews: getEntityViews, |
||||
|
getTenantEntityViews: getTenantEntityViews, |
||||
|
saveEntityView: saveEntityView, |
||||
|
unassignEntityViewFromCustomer: unassignEntityViewFromCustomer, |
||||
|
getEntityViewAttributes: getEntityViewAttributes, |
||||
|
subscribeForEntityViewAttributes: subscribeForEntityViewAttributes, |
||||
|
unsubscribeForEntityViewAttributes: unsubscribeForEntityViewAttributes, |
||||
|
findByQuery: findByQuery, |
||||
|
getEntityViewTypes: getEntityViewTypes |
||||
|
} |
||||
|
|
||||
|
return service; |
||||
|
|
||||
|
function getTenantEntityViews(pageLink, applyCustomersInfo, config, type) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/tenant/entityViews?limit=' + pageLink.limit; |
||||
|
if (angular.isDefined(pageLink.textSearch)) { |
||||
|
url += '&textSearch=' + pageLink.textSearch; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.idOffset)) { |
||||
|
url += '&idOffset=' + pageLink.idOffset; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.textOffset)) { |
||||
|
url += '&textOffset=' + pageLink.textOffset; |
||||
|
} |
||||
|
if (angular.isDefined(type) && type.length) { |
||||
|
url += '&type=' + type; |
||||
|
} |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
if (applyCustomersInfo) { |
||||
|
customerService.applyAssignedCustomersInfo(response.data.data).then( |
||||
|
function success(data) { |
||||
|
response.data.data = data; |
||||
|
deferred.resolve(response.data); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
deferred.resolve(response.data); |
||||
|
} |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getCustomerEntityViews(customerId, pageLink, applyCustomersInfo, config, type) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/customer/' + customerId + '/entityViews?limit=' + pageLink.limit; |
||||
|
if (angular.isDefined(pageLink.textSearch)) { |
||||
|
url += '&textSearch=' + pageLink.textSearch; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.idOffset)) { |
||||
|
url += '&idOffset=' + pageLink.idOffset; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.textOffset)) { |
||||
|
url += '&textOffset=' + pageLink.textOffset; |
||||
|
} |
||||
|
if (angular.isDefined(type) && type.length) { |
||||
|
url += '&type=' + type; |
||||
|
} |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
if (applyCustomersInfo) { |
||||
|
customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( |
||||
|
function success(data) { |
||||
|
response.data.data = data; |
||||
|
deferred.resolve(response.data); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
deferred.resolve(response.data); |
||||
|
} |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
|
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntityView(entityViewId, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/entityView/' + entityViewId; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntityViews(entityViewIds, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var ids = ''; |
||||
|
for (var i=0;i<entityViewIds.length;i++) { |
||||
|
if (i>0) { |
||||
|
ids += ','; |
||||
|
} |
||||
|
ids += entityViewIds[i]; |
||||
|
} |
||||
|
var url = '/api/entityViews?entityViewIds=' + ids; |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
var entityViews = response.data; |
||||
|
entityViews.sort(function (entityView1, entityView2) { |
||||
|
var id1 = entityView1.id.id; |
||||
|
var id2 = entityView2.id.id; |
||||
|
var index1 = entityViewIds.indexOf(id1); |
||||
|
var index2 = entityViewIds.indexOf(id2); |
||||
|
return index1 - index2; |
||||
|
}); |
||||
|
deferred.resolve(entityViews); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function saveEntityView(entityView) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/entityView'; |
||||
|
$http.post(url, entityView).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function deleteEntityView(entityViewId) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/entityView/' + entityViewId; |
||||
|
$http.delete(url).then(function success() { |
||||
|
deferred.resolve(); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function assignEntityViewToCustomer(customerId, entityViewId) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/customer/' + customerId + '/entityView/' + entityViewId; |
||||
|
$http.post(url, null).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function unassignEntityViewFromCustomer(entityViewId) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/customer/entityView/' + entityViewId; |
||||
|
$http.delete(url).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntityViewAttributes(entityViewId, attributeScope, query, successCallback, config) { |
||||
|
return attributeService.getEntityAttributes(types.entityType.entityView, entityViewId, attributeScope, query, successCallback, config); |
||||
|
} |
||||
|
|
||||
|
function subscribeForEntityViewAttributes(entityViewId, attributeScope) { |
||||
|
return attributeService.subscribeForEntityAttributes(types.entityType.entityView, entityViewId, attributeScope); |
||||
|
} |
||||
|
|
||||
|
function unsubscribeForEntityViewAttributes(subscriptionId) { |
||||
|
attributeService.unsubscribeForEntityAttributes(subscriptionId); |
||||
|
} |
||||
|
|
||||
|
function findByQuery(query, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/entityViews'; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.post(url, query, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntityViewTypes(config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/entityView/types'; |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 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. |
||||
|
|
||||
|
--> |
||||
|
<md-dialog aria-label="{{ 'entity-view.add' | translate }}" tb-help="'entityViews'" help-container-id="help-container"> |
||||
|
<form name="theForm" ng-submit="vm.add()"> |
||||
|
<md-toolbar> |
||||
|
<div class="md-toolbar-tools"> |
||||
|
<h2 translate>entity-view.add</h2> |
||||
|
<span flex></span> |
||||
|
<div id="help-container"></div> |
||||
|
<md-button class="md-icon-button" ng-click="vm.cancel()"> |
||||
|
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
</md-toolbar> |
||||
|
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> |
||||
|
<span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
||||
|
<md-dialog-content> |
||||
|
<div class="md-dialog-content"> |
||||
|
<tb-entity-view entity-view="vm.item" is-edit="true" the-form="theForm"></tb-entity-view> |
||||
|
</div> |
||||
|
</md-dialog-content> |
||||
|
<md-dialog-actions layout="row"> |
||||
|
<span flex></span> |
||||
|
<md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> |
||||
|
{{ 'action.add' | translate }} |
||||
|
</md-button> |
||||
|
<md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> |
||||
|
</md-dialog-actions> |
||||
|
</form> |
||||
|
</md-dialog> |
||||
@ -0,0 +1,123 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2018 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 AddEntityViewsToCustomerController(entityViewService, $mdDialog, $q, customerId, entityViews) { |
||||
|
|
||||
|
var vm = this; |
||||
|
|
||||
|
vm.entityViews = entityViews; |
||||
|
vm.searchText = ''; |
||||
|
|
||||
|
vm.assign = assign; |
||||
|
vm.cancel = cancel; |
||||
|
vm.hasData = hasData; |
||||
|
vm.noData = noData; |
||||
|
vm.searchEntityViewTextUpdated = searchEntityViewTextUpdated; |
||||
|
vm.toggleEntityViewSelection = toggleEntityViewSelection; |
||||
|
|
||||
|
vm.theEntityViews = { |
||||
|
getItemAtIndex: function (index) { |
||||
|
if (index > vm.entityViews.data.length) { |
||||
|
vm.theEntityViews.fetchMoreItems_(index); |
||||
|
return null; |
||||
|
} |
||||
|
var item = vm.entityViews.data[index]; |
||||
|
if (item) { |
||||
|
item.indexNumber = index + 1; |
||||
|
} |
||||
|
return item; |
||||
|
}, |
||||
|
|
||||
|
getLength: function () { |
||||
|
if (vm.entityViews.hasNext) { |
||||
|
return vm.entityViews.data.length + vm.entityViews.nextPageLink.limit; |
||||
|
} else { |
||||
|
return vm.entityViews.data.length; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
fetchMoreItems_: function () { |
||||
|
if (vm.entityViews.hasNext && !vm.entityViews.pending) { |
||||
|
vm.entityViews.pending = true; |
||||
|
entityViewService.getTenantEntityViews(vm.entityViews.nextPageLink, false).then( |
||||
|
function success(entityViews) { |
||||
|
vm.entityViews.data = vm.entityViews.data.concat(entityViews.data); |
||||
|
vm.entityViews.nextPageLink = entityViews.nextPageLink; |
||||
|
vm.entityViews.hasNext = entityViews.hasNext; |
||||
|
if (vm.entityViews.hasNext) { |
||||
|
vm.entityViews.nextPageLink.limit = vm.entityViews.pageSize; |
||||
|
} |
||||
|
vm.entityViews.pending = false; |
||||
|
}, |
||||
|
function fail() { |
||||
|
vm.entityViews.hasNext = false; |
||||
|
vm.entityViews.pending = false; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
function cancel () { |
||||
|
$mdDialog.cancel(); |
||||
|
} |
||||
|
|
||||
|
function assign() { |
||||
|
var tasks = []; |
||||
|
for (var entityViewId in vm.entityViews.selections) { |
||||
|
tasks.push(entityViewService.assignEntityViewToCustomer(customerId, entityViewId)); |
||||
|
} |
||||
|
$q.all(tasks).then(function () { |
||||
|
$mdDialog.hide(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function noData() { |
||||
|
return vm.entityViews.data.length == 0 && !vm.entityViews.hasNext; |
||||
|
} |
||||
|
|
||||
|
function hasData() { |
||||
|
return vm.entityViews.data.length > 0; |
||||
|
} |
||||
|
|
||||
|
function toggleEntityViewSelection($event, entityView) { |
||||
|
$event.stopPropagation(); |
||||
|
var selected = angular.isDefined(entityView.selected) && entityView.selected; |
||||
|
entityView.selected = !selected; |
||||
|
if (entityView.selected) { |
||||
|
vm.entityViews.selections[entityView.id.id] = true; |
||||
|
vm.entityViews.selectedCount++; |
||||
|
} else { |
||||
|
delete vm.entityViews.selections[entityView.id.id]; |
||||
|
vm.entityViews.selectedCount--; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function searchEntityViewTextUpdated() { |
||||
|
vm.entityViews = { |
||||
|
pageSize: vm.entityViews.pageSize, |
||||
|
data: [], |
||||
|
nextPageLink: { |
||||
|
limit: vm.entityViews.pageSize, |
||||
|
textSearch: vm.searchText |
||||
|
}, |
||||
|
selections: {}, |
||||
|
selectedCount: 0, |
||||
|
hasNext: true, |
||||
|
pending: false |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 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. |
||||
|
|
||||
|
--> |
||||
|
<md-dialog aria-label="{{ 'entity-view.assign-to-customer' | translate }}"> |
||||
|
<form name="theForm" ng-submit="vm.assign()"> |
||||
|
<md-toolbar> |
||||
|
<div class="md-toolbar-tools"> |
||||
|
<h2 translate>entity-view.assign-entity-view-to-customer</h2> |
||||
|
<span flex></span> |
||||
|
<md-button class="md-icon-button" ng-click="vm.cancel()"> |
||||
|
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
</md-toolbar> |
||||
|
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> |
||||
|
<span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
||||
|
<md-dialog-content> |
||||
|
<div class="md-dialog-content"> |
||||
|
<fieldset> |
||||
|
<span translate>entity-view.assign-entity-view-to-customer-text</span> |
||||
|
<md-input-container class="md-block" style='margin-bottom: 0px;'> |
||||
|
<label> </label> |
||||
|
<md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons"> |
||||
|
search |
||||
|
</md-icon> |
||||
|
<input id="entity-view-search" autofocus ng-model="vm.searchText" |
||||
|
ng-change="vm.searchEntityViewTextUpdated()" |
||||
|
placeholder="{{ 'common.enter-search' | translate }}"/> |
||||
|
</md-input-container> |
||||
|
<div style='min-height: 150px;'> |
||||
|
<span translate layout-align="center center" |
||||
|
style="text-transform: uppercase; display: flex; height: 150px;" |
||||
|
class="md-subhead" |
||||
|
ng-show="vm.noData()">entity-view.no-entity-views-text</span> |
||||
|
<md-virtual-repeat-container ng-show="vm.hasData()" |
||||
|
tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex |
||||
|
style='min-height: 150px; width: 100%;'> |
||||
|
<md-list> |
||||
|
<md-list-item md-virtual-repeat="entityView in vm.theEntityViews" md-on-demand |
||||
|
class="repeated-item" flex> |
||||
|
<md-checkbox ng-click="vm.toggleEntityViewSelection($event, entityView)" |
||||
|
aria-label="{{ 'item.selected' | translate }}" |
||||
|
ng-checked="entityView.selected"></md-checkbox> |
||||
|
<span> {{ entityView.name }} </span> |
||||
|
</md-list-item> |
||||
|
</md-list> |
||||
|
</md-virtual-repeat-container> |
||||
|
</div> |
||||
|
</fieldset> |
||||
|
</div> |
||||
|
</md-dialog-content> |
||||
|
<md-dialog-actions layout="row"> |
||||
|
<span flex></span> |
||||
|
<md-button ng-disabled="$root.loading || vm.entityViews.selectedCount == 0" type="submit" |
||||
|
class="md-raised md-primary"> |
||||
|
{{ 'action.assign' | translate }} |
||||
|
</md-button> |
||||
|
<md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | |
||||
|
translate }} |
||||
|
</md-button> |
||||
|
</md-dialog-actions> |
||||
|
</form> |
||||
|
</md-dialog> |
||||
@ -0,0 +1,123 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2018 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 AssignEntityViewToCustomerController(customerService, entityViewService, $mdDialog, $q, entityViewIds, 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 < entityViewIds.length;i++) { |
||||
|
tasks.push(entityViewService.assignEntityViewToCustomer(vm.customers.selection.id.id, entityViewIds[i])); |
||||
|
} |
||||
|
$q.all(tasks).then(function () { |
||||
|
$mdDialog.hide(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function noData() { |
||||
|
return vm.customers.data.length == 0 && !vm.customers.hasNext; |
||||
|
} |
||||
|
|
||||
|
function hasData() { |
||||
|
return vm.customers.data.length > 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 |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,76 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 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. |
||||
|
|
||||
|
--> |
||||
|
<md-dialog aria-label="{{ 'entity-view.assign-entity-view-to-customer' | translate }}"> |
||||
|
<form name="theForm" ng-submit="vm.assign()"> |
||||
|
<md-toolbar> |
||||
|
<div class="md-toolbar-tools"> |
||||
|
<h2 translate>entity-view.assign-entity-view-to-customer</h2> |
||||
|
<span flex></span> |
||||
|
<md-button class="md-icon-button" ng-click="vm.cancel()"> |
||||
|
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
</md-toolbar> |
||||
|
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> |
||||
|
<span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
||||
|
<md-dialog-content> |
||||
|
<div class="md-dialog-content"> |
||||
|
<fieldset> |
||||
|
<span translate>entity-view.assign-to-customer-text</span> |
||||
|
<md-input-container class="md-block" style='margin-bottom: 0px;'> |
||||
|
<label> </label> |
||||
|
<md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons"> |
||||
|
search |
||||
|
</md-icon> |
||||
|
<input id="customer-search" autofocus ng-model="vm.searchText" |
||||
|
ng-change="vm.searchCustomerTextUpdated()" |
||||
|
placeholder="{{ 'common.enter-search' | translate }}"/> |
||||
|
</md-input-container> |
||||
|
<div style='min-height: 150px;'> |
||||
|
<span translate layout-align="center center" |
||||
|
style="text-transform: uppercase; display: flex; height: 150px;" |
||||
|
class="md-subhead" |
||||
|
ng-show="vm.noData()">customer.no-customers-text</span> |
||||
|
<md-virtual-repeat-container ng-show="vm.hasData()" |
||||
|
tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex |
||||
|
style='min-height: 150px; width: 100%;'> |
||||
|
<md-list> |
||||
|
<md-list-item md-virtual-repeat="customer in vm.theCustomers" md-on-demand |
||||
|
class="repeated-item" flex> |
||||
|
<md-checkbox ng-click="vm.toggleCustomerSelection($event, customer)" |
||||
|
aria-label="{{ 'item.selected' | translate }}" |
||||
|
ng-checked="vm.isCustomerSelected(customer)"></md-checkbox> |
||||
|
<span> {{ customer.title }} </span> |
||||
|
</md-list-item> |
||||
|
</md-list> |
||||
|
</md-virtual-repeat-container> |
||||
|
</div> |
||||
|
</fieldset> |
||||
|
</div> |
||||
|
</md-dialog-content> |
||||
|
<md-dialog-actions layout="row"> |
||||
|
<span flex></span> |
||||
|
<md-button ng-disabled="$root.loading || vm.customers.selection==null" type="submit" class="md-raised md-primary"> |
||||
|
{{ 'action.assign' | translate }} |
||||
|
</md-button> |
||||
|
<md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | |
||||
|
translate }} |
||||
|
</md-button> |
||||
|
</md-dialog-actions> |
||||
|
</form> |
||||
|
</md-dialog> |
||||
@ -0,0 +1,22 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 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 flex layout="column" style="margin-top: -10px;"> |
||||
|
<div style="text-transform: uppercase; padding-bottom: 5px;">{{vm.item.type}}</div> |
||||
|
<div class="tb-card-description">{{vm.item.additionalInfo.description}}</div> |
||||
|
<div style="padding-top: 5px;" class="tb-small" ng-show="vm.isAssignedToCustomer()">{{'entity-view.assignedToCustomer' | translate}} '{{vm.item.assignedCustomer.title}}'</div> |
||||
|
</div> |
||||
@ -0,0 +1,64 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 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. |
||||
|
|
||||
|
--> |
||||
|
<md-button ng-click="onAssignToCustomer({event: $event})" |
||||
|
ng-show="!isEdit && entityViewScope === 'tenant' && !isAssignedToCustomer" |
||||
|
class="md-raised md-primary">{{ 'entity-view.assign-to-customer' | translate }}</md-button> |
||||
|
<md-button ng-click="onUnassignFromCustomer({event: $event})" |
||||
|
ng-show="!isEdit && (entityViewScope === 'customer' || entityViewScope === 'tenant') && isAssignedToCustomer" |
||||
|
class="md-raised md-primary">{{'entity-view.unassign-from-customer' | translate }}</md-button> |
||||
|
<md-button ng-click="onDeleteEntityView({event: $event})" |
||||
|
ng-show="!isEdit && entityViewScope === 'tenant'" |
||||
|
class="md-raised md-primary">{{ 'entity-view.delete' | translate }}</md-button> |
||||
|
|
||||
|
<div layout="row"> |
||||
|
<md-button ngclipboard data-clipboard-action="copy" |
||||
|
ngclipboard-success="onEntityViewIdCopied(e)" |
||||
|
data-clipboard-text="{{entityView.id.id}}" ng-show="!isEdit" |
||||
|
class="md-raised"> |
||||
|
<md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon> |
||||
|
<span translate>entity-view.copyId</span> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
|
||||
|
<md-content class="md-padding" layout="column"> |
||||
|
<md-input-container class="md-block" |
||||
|
ng-show="!isEdit && isAssignedToCustomer && entityViewScope === 'tenant'"> |
||||
|
<label translate>entity-view.assignedToCustomer</label> |
||||
|
<input ng-model="assignedCustomer.title" disabled> |
||||
|
</md-input-container> |
||||
|
<fieldset ng-disabled="$root.loading || !isEdit"> |
||||
|
<md-input-container class="md-block"> |
||||
|
<label translate>entity-view.name</label> |
||||
|
<input required name="name" ng-model="entityView.name"> |
||||
|
<div ng-messages="theForm.name.$error"> |
||||
|
<div translate ng-message="required">entity-view.name-required</div> |
||||
|
</div> |
||||
|
</md-input-container> |
||||
|
<tb-entity-subtype-autocomplete |
||||
|
ng-disabled="$root.loading || !isEdit" |
||||
|
tb-required="true" |
||||
|
the-form="theForm" |
||||
|
ng-model="entityView.type" |
||||
|
entity-type="types.entityType.entityview"> |
||||
|
</tb-entity-subtype-autocomplete> |
||||
|
<md-input-container class="md-block"> |
||||
|
<label translate>entity-view.description</label> |
||||
|
<textarea ng-model="entityView.additionalInfo.description" rows="2"></textarea> |
||||
|
</md-input-container> |
||||
|
</fieldset> |
||||
|
</md-content> |
||||
@ -0,0 +1,483 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2018 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. |
||||
|
*/ |
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import addEntityViewTemplate from './add-entity-view.tpl.html'; |
||||
|
import entityViewCard from './entity-view-card.tpl.html'; |
||||
|
import assignToCustomerTemplate from './assign-to-customer.tpl.html'; |
||||
|
import addEntityViewsToCustomerTemplate from './add-entity-views-to-customer.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export function EntityViewCardController(types) { |
||||
|
|
||||
|
var vm = this; |
||||
|
|
||||
|
vm.types = types; |
||||
|
|
||||
|
vm.isAssignedToCustomer = function() { |
||||
|
if (vm.item && vm.item.customerId && vm.parentCtl.entityViewsScope === '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.entityViewsScope === 'tenant' && vm.item.assignedCustomer.isPublic) { |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export function EntityViewController($rootScope, userService, entityViewService, customerService, $state, $stateParams, |
||||
|
$document, $mdDialog, $q, $translate, types) { |
||||
|
|
||||
|
var customerId = $stateParams.customerId; |
||||
|
|
||||
|
var entityViewActionsList = []; |
||||
|
|
||||
|
var entityViewGroupActionsList = []; |
||||
|
|
||||
|
var vm = this; |
||||
|
|
||||
|
vm.types = types; |
||||
|
|
||||
|
vm.entityViewGridConfig = { |
||||
|
deleteItemTitleFunc: deleteEntityViewTitle, |
||||
|
deleteItemContentFunc: deleteEntityViewText, |
||||
|
deleteItemsTitleFunc: deleteEntityViewsTitle, |
||||
|
deleteItemsActionTitleFunc: deleteEntityViewsActionTitle, |
||||
|
deleteItemsContentFunc: deleteEntityViewsText, |
||||
|
|
||||
|
saveItemFunc: saveEntityView, |
||||
|
|
||||
|
getItemTitleFunc: getEntityViewTitle, |
||||
|
|
||||
|
itemCardController: 'EntityViewCardController', |
||||
|
itemCardTemplateUrl: entityViewCard, |
||||
|
parentCtl: vm, |
||||
|
|
||||
|
actionsList: entityViewActionsList, |
||||
|
groupActionsList: entityViewGroupActionsList, |
||||
|
|
||||
|
onGridInited: gridInited, |
||||
|
|
||||
|
addItemTemplateUrl: addEntityViewTemplate, |
||||
|
|
||||
|
addItemText: function() { return $translate.instant('entity-view.add-entity-view-text') }, |
||||
|
noItemsText: function() { return $translate.instant('entity-view.no-entity-views-text') }, |
||||
|
itemDetailsText: function() { return $translate.instant('entity-view.entity-view-details') }, |
||||
|
isDetailsReadOnly: isCustomerUser, |
||||
|
isSelectionEnabled: function () { |
||||
|
return !isCustomerUser(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
if (angular.isDefined($stateParams.items) && $stateParams.items !== null) { |
||||
|
vm.entityViewGridConfig.items = $stateParams.items; |
||||
|
} |
||||
|
|
||||
|
if (angular.isDefined($stateParams.topIndex) && $stateParams.topIndex > 0) { |
||||
|
vm.entityViewGridConfig.topIndex = $stateParams.topIndex; |
||||
|
} |
||||
|
|
||||
|
vm.entityViewsScope = $state.$current.data.entityViewsType; |
||||
|
|
||||
|
vm.assignToCustomer = assignToCustomer; |
||||
|
vm.makePublic = makePublic; |
||||
|
vm.unassignFromCustomer = unassignFromCustomer; |
||||
|
|
||||
|
initController(); |
||||
|
|
||||
|
function initController() { |
||||
|
var fetchEntityViewsFunction = null; |
||||
|
var deleteEntityViewFunction = null; |
||||
|
var refreshEntityViewsParamsFunction = null; |
||||
|
|
||||
|
var user = userService.getCurrentUser(); |
||||
|
|
||||
|
if (user.authority === 'CUSTOMER_USER') { |
||||
|
vm.entityViewsScope = 'customer_user'; |
||||
|
customerId = user.customerId; |
||||
|
} |
||||
|
if (customerId) { |
||||
|
vm.customerEntityViewsTitle = $translate.instant('customer.entity-views'); |
||||
|
customerService.getShortCustomerInfo(customerId).then( |
||||
|
function success(info) { |
||||
|
if (info.isPublic) { |
||||
|
vm.customerEntityViewsTitle = $translate.instant('customer.public-entity-views'); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
if (vm.entityViewsScope === 'tenant') { |
||||
|
fetchEntityViewsFunction = function (pageLink, entityViewType) { |
||||
|
return entityViewService.getTenantEntityViews(pageLink, true, null, entityViewType); |
||||
|
}; |
||||
|
deleteEntityViewFunction = function (entityViewId) { |
||||
|
return entityViewService.deleteEntityView(entityViewId); |
||||
|
}; |
||||
|
refreshEntityViewsParamsFunction = function() { |
||||
|
return {"topIndex": vm.topIndex}; |
||||
|
}; |
||||
|
|
||||
|
entityViewActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event, item) { |
||||
|
assignToCustomer($event, [ item.id.id ]); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('action.assign') }, |
||||
|
details: function() { return $translate.instant('entity-view.assign-to-customer') }, |
||||
|
icon: "assignment_ind", |
||||
|
isEnabled: function(entityView) { |
||||
|
return entityView && (!entityView.customerId || entityView.customerId.id === types.id.nullUid); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
entityViewActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event, item) { |
||||
|
unassignFromCustomer($event, item, false); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('action.unassign') }, |
||||
|
details: function() { return $translate.instant('entity-view.unassign-from-customer') }, |
||||
|
icon: "assignment_return", |
||||
|
isEnabled: function(entityView) { |
||||
|
return entityView && entityView.customerId && entityView.customerId.id !== types.id.nullUid && !entityView.assignedCustomer.isPublic; |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
entityViewActionsList.push({ |
||||
|
onAction: function ($event, item) { |
||||
|
unassignFromCustomer($event, item, true); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('action.make-private') }, |
||||
|
details: function() { return $translate.instant('entity-view.make-private') }, |
||||
|
icon: "reply", |
||||
|
isEnabled: function(entityView) { |
||||
|
return entityView && entityView.customerId && entityView.customerId.id !== types.id.nullUid && entityView.assignedCustomer.isPublic; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
entityViewActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event, item) { |
||||
|
vm.grid.deleteItem($event, item); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('action.delete') }, |
||||
|
details: function() { return $translate.instant('entity-view.delete') }, |
||||
|
icon: "delete" |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
entityViewGroupActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event, items) { |
||||
|
assignEntiyViewsToCustomer($event, items); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('entity-view.assign-entity-views') }, |
||||
|
details: function(selectedCount) { |
||||
|
return $translate.instant('entity-view.assign-entity-views-text', {count: selectedCount}, "messageformat"); |
||||
|
}, |
||||
|
icon: "assignment_ind" |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
entityViewGroupActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event) { |
||||
|
vm.grid.deleteItems($event); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('entity-view.delete-entity-views') }, |
||||
|
details: deleteEntityViewsActionTitle, |
||||
|
icon: "delete" |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
|
||||
|
|
||||
|
} else if (vm.entityViewsScope === 'customer' || vm.entityViewsScope === 'customer_user') { |
||||
|
fetchEntityViewsFunction = function (pageLink, entityViewType) { |
||||
|
return entityViewService.getCustomerEntityViews(customerId, pageLink, true, null, entityViewType); |
||||
|
}; |
||||
|
deleteentityViewFunction = function (entityViewId) { |
||||
|
return entityViewService.unassignEntityViewFromCustomer(entityViewId); |
||||
|
}; |
||||
|
refreshentityViewsParamsFunction = function () { |
||||
|
return {"customerId": customerId, "topIndex": vm.topIndex}; |
||||
|
}; |
||||
|
|
||||
|
if (vm.entityViewsScope === 'customer') { |
||||
|
entityViewActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event, item) { |
||||
|
unassignFromCustomer($event, item, false); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('action.unassign') }, |
||||
|
details: function() { return $translate.instant('entity-view.unassign-from-customer') }, |
||||
|
icon: "assignment_return", |
||||
|
isEnabled: function(entityView) { |
||||
|
return entityView && !entityView.assignedCustomer.isPublic; |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
entityViewGroupActionsList.push( |
||||
|
{ |
||||
|
onAction: function ($event, items) { |
||||
|
unassignEntityViewsFromCustomer($event, items); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('entity-view.unassign-entity-views') }, |
||||
|
details: function(selectedCount) { |
||||
|
return $translate.instant('entity-view.unassign-entity-views-action-title', {count: selectedCount}, "messageformat"); |
||||
|
}, |
||||
|
icon: "assignment_return" |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
vm.entityViewGridConfig.addItemAction = { |
||||
|
onAction: function ($event) { |
||||
|
addEntityViewsToCustomer($event); |
||||
|
}, |
||||
|
name: function() { return $translate.instant('entity-view.assign-entity-views') }, |
||||
|
details: function() { return $translate.instant('entity-view.assign-new-entity-view') }, |
||||
|
icon: "add" |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
} else if (vm.entityViewsScope === 'customer_user') { |
||||
|
vm.entityViewGridConfig.addItemAction = {}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
vm.entityViewGridConfig.refreshParamsFunc = refreshentityViewsParamsFunction; |
||||
|
vm.entityViewGridConfig.fetchItemsFunc = fetchentityViewsFunction; |
||||
|
vm.entityViewGridConfig.deleteItemFunc = deleteentityViewFunction; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
function deleteEntityViewTitle(entityView) { |
||||
|
return $translate.instant('entity-view.delete-entity-view-title', {entityViewName: entityView.name}); |
||||
|
} |
||||
|
|
||||
|
function deleteEntityViewText() { |
||||
|
return $translate.instant('entity-view.delete-entity-view-text'); |
||||
|
} |
||||
|
|
||||
|
function deleteEntityViewsTitle(selectedCount) { |
||||
|
return $translate.instant('entity-view.delete-entity-views-title', {count: selectedCount}, 'messageformat'); |
||||
|
} |
||||
|
|
||||
|
function deleteEntityViewsActionTitle(selectedCount) { |
||||
|
return $translate.instant('entity-view.delete-entity-views-action-title', {count: selectedCount}, 'messageformat'); |
||||
|
} |
||||
|
|
||||
|
function deleteEntityViewsText () { |
||||
|
return $translate.instant('entity-view.delete-entity-views-text'); |
||||
|
} |
||||
|
|
||||
|
function gridInited(grid) { |
||||
|
vm.grid = grid; |
||||
|
} |
||||
|
|
||||
|
function getEntityViewTitle(entityView) { |
||||
|
return entityView ? entityView.name : ''; |
||||
|
} |
||||
|
|
||||
|
function saveEntityView(entityView) { |
||||
|
var deferred = $q.defer(); |
||||
|
entityViewService.saveEntityView(entityView).then( |
||||
|
function success(savedEntityView) { |
||||
|
$rootScope.$broadcast('entityViewSaved'); |
||||
|
var entityViews = [ savedEntityView ]; |
||||
|
customerService.applyAssignedCustomersInfo(entityViews).then( |
||||
|
function success(items) { |
||||
|
if (items && items.length == 1) { |
||||
|
deferred.resolve(items[0]); |
||||
|
} else { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function isCustomerUser() { |
||||
|
return vm.entityViewsScope === 'customer_user'; |
||||
|
} |
||||
|
|
||||
|
function assignToCustomer($event, entityViewIds) { |
||||
|
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: 'AssignEntityViewToCustomerController', |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: assignToCustomerTemplate, |
||||
|
locals: {entityViewIds: entityViewIds, customers: customers}, |
||||
|
parent: angular.element($document[0].body), |
||||
|
fullscreen: true, |
||||
|
targetEvent: $event |
||||
|
}).then(function () { |
||||
|
vm.grid.refreshList(); |
||||
|
}, function () { |
||||
|
}); |
||||
|
}, |
||||
|
function fail() { |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function addEntityViewsToCustomer($event) { |
||||
|
if ($event) { |
||||
|
$event.stopPropagation(); |
||||
|
} |
||||
|
var pageSize = 10; |
||||
|
entityViewService.getTenantEntityViews({limit: pageSize, textSearch: ''}, false).then( |
||||
|
function success(_entityViews) { |
||||
|
var entityViews = { |
||||
|
pageSize: pageSize, |
||||
|
data: _entityViews.data, |
||||
|
nextPageLink: _entityViews.nextPageLink, |
||||
|
selections: {}, |
||||
|
selectedCount: 0, |
||||
|
hasNext: _entityViews.hasNext, |
||||
|
pending: false |
||||
|
}; |
||||
|
if (entityViews.hasNext) { |
||||
|
entityViews.nextPageLink.limit = pageSize; |
||||
|
} |
||||
|
$mdDialog.show({ |
||||
|
controller: 'AddEntityViewsToCustomerController', |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: addEntityViewsToCustomerTemplate, |
||||
|
locals: {customerId: customerId, entityViews: entityViews}, |
||||
|
parent: angular.element($document[0].body), |
||||
|
fullscreen: true, |
||||
|
targetEvent: $event |
||||
|
}).then(function () { |
||||
|
vm.grid.refreshList(); |
||||
|
}, function () { |
||||
|
}); |
||||
|
}, |
||||
|
function fail() { |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function assignEntityViewsToCustomer($event, items) { |
||||
|
var entityViewIds = []; |
||||
|
for (var id in items.selections) { |
||||
|
entityViewIds.push(id); |
||||
|
} |
||||
|
assignToCustomer($event, entityViewIds); |
||||
|
} |
||||
|
|
||||
|
function unassignFromCustomer($event, entityView, isPublic) { |
||||
|
if ($event) { |
||||
|
$event.stopPropagation(); |
||||
|
} |
||||
|
var title; |
||||
|
var content; |
||||
|
var label; |
||||
|
if (isPublic) { |
||||
|
title = $translate.instant('entity-view.make-private-entity-view-title', {entityViewName: entityView.name}); |
||||
|
content = $translate.instant('entity-view.make-private-entity-view-text'); |
||||
|
label = $translate.instant('entity-view.make-private'); |
||||
|
} else { |
||||
|
title = $translate.instant('entity-view.unassign-entity-view-title', {entityViewName: entityView.name}); |
||||
|
content = $translate.instant('entity-view.unassign-entity-view-text'); |
||||
|
label = $translate.instant('entity-view.unassign-entity-view'); |
||||
|
} |
||||
|
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 () { |
||||
|
entityViewService.unassignEntityViewFromCustomer(entityView.id.id).then(function success() { |
||||
|
vm.grid.refreshList(); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function unassignEntityViewsFromCustomer($event, items) { |
||||
|
var confirm = $mdDialog.confirm() |
||||
|
.targetEvent($event) |
||||
|
.title($translate.instant('entity-view.unassign-entity-views-title', {count: items.selectedCount}, 'messageformat')) |
||||
|
.htmlContent($translate.instant('entity-view.unassign-entity-views-text')) |
||||
|
.ariaLabel($translate.instant('entity-view.unassign-entity-view')) |
||||
|
.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(entityViewService.unassignEntityViewFromCustomer(id)); |
||||
|
} |
||||
|
$q.all(tasks).then(function () { |
||||
|
vm.grid.refreshList(); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function makePublic($event, entityView) { |
||||
|
if ($event) { |
||||
|
$event.stopPropagation(); |
||||
|
} |
||||
|
var confirm = $mdDialog.confirm() |
||||
|
.targetEvent($event) |
||||
|
.title($translate.instant('entity-view.make-public-entity-view-title', {entityViewName: entityView.name})) |
||||
|
.htmlContent($translate.instant('entity-view.make-public-entity-view-text')) |
||||
|
.ariaLabel($translate.instant('entity-view.make-public')) |
||||
|
.cancel($translate.instant('action.no')) |
||||
|
.ok($translate.instant('action.yes')); |
||||
|
$mdDialog.show(confirm).then(function () { |
||||
|
entityViewService.makeEntityViewPublic(entityView.id.id).then(function success() { |
||||
|
vm.grid.refreshList(); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2018 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. |
||||
|
*/ |
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export default function EntityViewDirective($compile, $templateCache, toast, $translate, types, clipboardService, entityViewService, customerService) { |
||||
|
var linker = function (scope, element) { |
||||
|
var template = $templateCache.get(entityViewFieldsetTemplate); |
||||
|
element.html(template); |
||||
|
|
||||
|
scope.types = types; |
||||
|
scope.isAssignedToCustomer = false; |
||||
|
scope.assignedCustomer = null; |
||||
|
|
||||
|
scope.$watch('entityView', function(newVal) { |
||||
|
if (newVal) { |
||||
|
if (scope.entityView.customerId && scope.entityView.customerId.id !== types.id.nullUid) { |
||||
|
scope.isAssignedToCustomer = true; |
||||
|
customerService.getShortCustomerInfo(scope.entityView.customerId.id).then( |
||||
|
function success(customer) { |
||||
|
scope.assignedCustomer = customer; |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
scope.isAssignedToCustomer = false; |
||||
|
scope.assignedCustomer = null; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
scope.onEntityViewIdCopied = function() { |
||||
|
toast.showSuccess($translate.instant('entity-view.idCopiedMessage'), 750, angular.element(element).parent().parent(), 'bottom left'); |
||||
|
}; |
||||
|
|
||||
|
$compile(element.contents())(scope); |
||||
|
} |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
link: linker, |
||||
|
scope: { |
||||
|
entityView: '=', |
||||
|
isEdit: '=', |
||||
|
entityViewScope: '=', |
||||
|
theForm: '=', |
||||
|
onAssignToCustomer: '&', |
||||
|
onUnassignFromCustomer: '&', |
||||
|
onDeleteEntityView: '&' |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2018 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. |
||||
|
*/ |
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import entityViewsTemplate from './entity-views.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
export default function EntityViewRoutes($stateProvider, types) { |
||||
|
$stateProvider |
||||
|
.state('home.entityViews', { |
||||
|
url: '/entityViews', |
||||
|
params: {'topIndex': 0}, |
||||
|
module: 'private', |
||||
|
auth: ['TENANT_ADMIN', 'CUSTOMER_USER'], |
||||
|
views: { |
||||
|
"content@home": { |
||||
|
templateUrl: entityViewsTemplate, |
||||
|
controller: 'EntityViewController', |
||||
|
controllerAs: 'vm' |
||||
|
} |
||||
|
}, |
||||
|
data: { |
||||
|
entityViewsTypes: 'tenant', |
||||
|
searchEnabled: true, |
||||
|
searchByEntitySubtype: true, |
||||
|
searchEntityType: types.entityType.entityview, |
||||
|
pageTitle: 'entity-views.entity-views' |
||||
|
}, |
||||
|
ncyBreadcrumb: { |
||||
|
label: '{"icon": "devices_other", "label": "entity-view.entity-views"}' |
||||
|
} |
||||
|
}) |
||||
|
.state('home.customers.entityViews', { |
||||
|
url: '/:customerId/entityViews', |
||||
|
params: {'topIndex': 0}, |
||||
|
module: 'private', |
||||
|
auth: ['TENANT_ADMIN'], |
||||
|
views: { |
||||
|
"content@home": { |
||||
|
templateUrl: entityViewsTemplate, |
||||
|
controllerAs: 'vm', |
||||
|
controller: 'EntityViewController' |
||||
|
} |
||||
|
}, |
||||
|
data: { |
||||
|
entityViewsTypes: 'customer', |
||||
|
searchEnabled: true, |
||||
|
searchByEntitySubtype: true, |
||||
|
searchEntityType: types.entityType.entityview, |
||||
|
pageTitle: 'customer.entity-views' |
||||
|
}, |
||||
|
ncyBreadcrumb: { |
||||
|
label: '{"icon": "devices_other", "label": "{{ vm.customerEntityViewsTitle }}", "translate": "false"}' |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 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-grid grid-configuration="vm.entityViewGridConfig"> |
||||
|
<details-buttons tb-help="'entityViews'" help-container-id="help-container"> |
||||
|
<div id="help-container"></div> |
||||
|
</details-buttons> |
||||
|
<md-tabs ng-class="{'tb-headless': vm.grid.detailsConfig.isDetailsEditMode}" |
||||
|
id="tabs" md-border-bottom flex class="tb-absolute-fill"> |
||||
|
<md-tab label="{{ 'entity-view.details' | translate }}"> |
||||
|
<tb-entity-view entity-view="vm.grid.operatingItem()" |
||||
|
is-edit="vm.grid.detailsConfig.isDetailsEditMode" |
||||
|
entity-view-scope="vm.entityViewsScope" |
||||
|
the-form="vm.grid.detailsForm" |
||||
|
on-assign-to-customer="vm.assignToCustomer(event, [ vm.grid.detailsConfig.currentItem.id.id ])" |
||||
|
on-make-public="vm.makePublic(event, vm.grid.detailsConfig.currentItem)" |
||||
|
on-unassign-from-customer="vm.unassignFromCustomer(event, vm.grid.detailsConfig.currentItem, isPublic)" |
||||
|
on-manage-credentials="vm.manageCredentials(event, vm.grid.detailsConfig.currentItem)" |
||||
|
on-delete-entity-view="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-entity-view> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}"> |
||||
|
<tb-attribute-table flex |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
entity-type="{{vm.types.entityType.entityview}}" |
||||
|
entity-name="vm.grid.operatingItem().name" |
||||
|
default-attribute-scope="{{vm.types.attributesScope.client.value}}"> |
||||
|
</tb-attribute-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}"> |
||||
|
<tb-attribute-table flex |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
entity-type="{{vm.types.entityType.entityview}}" |
||||
|
entity-name="vm.grid.operatingItem().name" |
||||
|
default-attribute-scope="{{vm.types.latestTelemetry.value}}" |
||||
|
disable-attribute-scope-selection="true"> |
||||
|
</tb-attribute-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}"> |
||||
|
<tb-alarm-table flex entity-type="vm.types.entityType.entityview" |
||||
|
entity-id="vm.grid.operatingItem().id.id"> |
||||
|
</tb-alarm-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'entity-view.events' | translate }}"> |
||||
|
<tb-event-table flex entity-type="vm.types.entityType.entityview" |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
tenant-id="vm.grid.operatingItem().tenantId.id" |
||||
|
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="{{ 'relation.relations' | translate }}"> |
||||
|
<tb-relation-table flex |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
entity-type="{{vm.types.entityType.entityview}}"> |
||||
|
</tb-relation-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.operatingItem().additionalInfo.gateway" md-on-select="vm.grid.triggerResize()" label="{{ 'extension.extensions' | translate }}"> |
||||
|
<tb-extension-table flex |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
entity-name="vm.grid.operatingItem().name" |
||||
|
entity-type="{{vm.types.entityType.entityview}}"> |
||||
|
</tb-extension-table> |
||||
|
</md-tab> |
||||
|
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.isTenantAdmin()" md-on-select="vm.grid.triggerResize()" label="{{ 'audit-log.audit-logs' | translate }}"> |
||||
|
<tb-audit-log-table flex entity-type="vm.types.entityType.entityview" |
||||
|
entity-id="vm.grid.operatingItem().id.id" |
||||
|
audit-log-mode="{{vm.types.auditLogMode.entity}}"> |
||||
|
</tb-audit-log-table> |
||||
|
</md-tab> |
||||
|
</tb-grid> |
||||
@ -0,0 +1,41 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2018 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 uiRouter from 'angular-ui-router'; |
||||
|
import thingsboardGrid from '../components/grid.directive'; |
||||
|
import thingsboardApiUser from '../api/user.service'; |
||||
|
import thingsboardApiEntityView from '../api/entity-view.service'; |
||||
|
import thingsboardApiCustomer from '../api/customer.service'; |
||||
|
|
||||
|
import EntityViewRoutes from './entity-view.routes'; |
||||
|
import EntityViewCardController from './entity-view.controller'; |
||||
|
import AssignEntityViewToCustomerController from './assign-to-customer.controller'; |
||||
|
import AddEntityViewsToCustomerController from './add-entity-views-to-customer.controller'; |
||||
|
import EntityViewDirective from './entity-view.directive'; |
||||
|
|
||||
|
export default angular.module('thingsboard.entityView', [ |
||||
|
uiRouter, |
||||
|
thingsboardGrid, |
||||
|
thingsboardApiUser, |
||||
|
thingsboardApiEntityView, |
||||
|
thingsboardApiCustomer |
||||
|
]) |
||||
|
.config(EntityViewRoutes) |
||||
|
.controller('EntityViewController', EntityViewCardController) |
||||
|
.controller('EntityViewCardController', EntityViewCardController) |
||||
|
.controller('AssignEntityViewToCustomerController', AssignEntityViewToCustomerController) |
||||
|
.controller('AddEntityViewsToCustomerController', AddEntityViewsToCustomerController) |
||||
|
.directive('tbEntityView', EntityViewDirective) |
||||
|
.name; |
||||
Loading…
Reference in new issue