committed by
GitHub
59 changed files with 1671 additions and 859 deletions
@ -0,0 +1,100 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2017 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.install; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.JavaType; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.csv.CSVFormat; |
||||
|
import org.apache.commons.csv.CSVParser; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.thingsboard.server.common.data.ShortCustomerInfo; |
||||
|
import org.thingsboard.server.common.data.UUIDConverter; |
||||
|
import org.thingsboard.server.common.data.id.CustomerId; |
||||
|
import org.thingsboard.server.common.data.id.DashboardId; |
||||
|
import org.thingsboard.server.dao.dashboard.DashboardService; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.nio.file.Files; |
||||
|
import java.nio.file.Path; |
||||
|
import java.util.*; |
||||
|
|
||||
|
/** |
||||
|
* Created by igor on 2/27/18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class DatabaseHelper { |
||||
|
|
||||
|
public static final CSVFormat CSV_DUMP_FORMAT = CSVFormat.DEFAULT.withNullString("\\N"); |
||||
|
|
||||
|
public static final String DEVICE = "device"; |
||||
|
public static final String TENANT_ID = "tenant_id"; |
||||
|
public static final String CUSTOMER_ID = "customer_id"; |
||||
|
public static final String SEARCH_TEXT = "search_text"; |
||||
|
public static final String ADDITIONAL_INFO = "additional_info"; |
||||
|
public static final String ASSET = "asset"; |
||||
|
public static final String DASHBOARD = "dashboard"; |
||||
|
public static final String ID = "id"; |
||||
|
public static final String TITLE = "title"; |
||||
|
public static final String ASSIGNED_CUSTOMERS = "assigned_customers"; |
||||
|
public static final String CONFIGURATION = "configuration"; |
||||
|
|
||||
|
public static final ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
|
||||
|
public static void upgradeTo40_assignDashboards(Path dashboardsDump, DashboardService dashboardService, boolean sql) throws Exception { |
||||
|
JavaType assignedCustomersType = |
||||
|
objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); |
||||
|
try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(dashboardsDump), CSV_DUMP_FORMAT.withFirstRecordAsHeader())) { |
||||
|
csvParser.forEach(record -> { |
||||
|
String customerIdString = record.get(CUSTOMER_ID); |
||||
|
String assignedCustomersString = record.get(ASSIGNED_CUSTOMERS); |
||||
|
DashboardId dashboardId = new DashboardId(toUUID(record.get(ID), sql)); |
||||
|
List<CustomerId> customerIds = new ArrayList<>(); |
||||
|
if (!StringUtils.isEmpty(assignedCustomersString)) { |
||||
|
try { |
||||
|
Set<ShortCustomerInfo> assignedCustomers = objectMapper.readValue(assignedCustomersString, assignedCustomersType); |
||||
|
assignedCustomers.forEach((customerInfo) -> { |
||||
|
CustomerId customerId = customerInfo.getCustomerId(); |
||||
|
if (!customerId.isNullUid()) { |
||||
|
customerIds.add(customerId); |
||||
|
} |
||||
|
}); |
||||
|
} catch (IOException e) { |
||||
|
log.error("Unable to parse assigned customers field", e); |
||||
|
} |
||||
|
} |
||||
|
if (!StringUtils.isEmpty(customerIdString)) { |
||||
|
CustomerId customerId = new CustomerId(toUUID(customerIdString, sql)); |
||||
|
if (!customerId.isNullUid()) { |
||||
|
customerIds.add(customerId); |
||||
|
} |
||||
|
} |
||||
|
for (CustomerId customerId : customerIds) { |
||||
|
dashboardService.assignDashboardToCustomer(dashboardId, customerId); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static UUID toUUID(String src, boolean sql) { |
||||
|
if (sql) { |
||||
|
return UUIDConverter.fromString(src); |
||||
|
} else { |
||||
|
return UUID.fromString(src); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,171 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2017 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.install.sql; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.csv.CSVFormat; |
||||
|
import org.apache.commons.csv.CSVParser; |
||||
|
import org.apache.commons.csv.CSVPrinter; |
||||
|
import org.apache.commons.csv.CSVRecord; |
||||
|
|
||||
|
import java.nio.file.Files; |
||||
|
import java.nio.file.Path; |
||||
|
import java.sql.*; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import static org.thingsboard.server.service.install.DatabaseHelper.CSV_DUMP_FORMAT; |
||||
|
|
||||
|
/** |
||||
|
* Created by igor on 2/27/18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class SqlDbHelper { |
||||
|
|
||||
|
public static Path dumpTableIfExists(Connection conn, String tableName, |
||||
|
String[] columns, String[] defaultValues, String dumpPrefix) throws Exception { |
||||
|
return dumpTableIfExists(conn, tableName, columns, defaultValues, dumpPrefix, false); |
||||
|
} |
||||
|
|
||||
|
public static Path dumpTableIfExists(Connection conn, String tableName, |
||||
|
String[] columns, String[] defaultValues, String dumpPrefix, boolean printHeader) throws Exception { |
||||
|
|
||||
|
if (tableExists(conn, tableName)) { |
||||
|
Path dumpFile = Files.createTempFile(dumpPrefix, null); |
||||
|
Files.deleteIfExists(dumpFile); |
||||
|
CSVFormat csvFormat = CSV_DUMP_FORMAT; |
||||
|
if (printHeader) { |
||||
|
csvFormat = csvFormat.withHeader(columns); |
||||
|
} |
||||
|
try (CSVPrinter csvPrinter = new CSVPrinter(Files.newBufferedWriter(dumpFile), csvFormat)) { |
||||
|
try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM " + tableName)) { |
||||
|
try (ResultSet tableRes = stmt.executeQuery()) { |
||||
|
ResultSetMetaData resMetaData = tableRes.getMetaData(); |
||||
|
Map<String, Integer> columnIndexMap = new HashMap<>(); |
||||
|
for (int i = 1; i <= resMetaData.getColumnCount(); i++) { |
||||
|
String columnName = resMetaData.getColumnName(i); |
||||
|
columnIndexMap.put(columnName.toUpperCase(), i); |
||||
|
} |
||||
|
while(tableRes.next()) { |
||||
|
dumpRow(tableRes, columnIndexMap, columns, defaultValues, csvPrinter); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return dumpFile; |
||||
|
} else { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static boolean tableExists(Connection conn, String tableName) { |
||||
|
try (Statement stmt = conn.createStatement()) { |
||||
|
stmt.executeQuery("select * from " + tableName + " where 1=0"); |
||||
|
return true; |
||||
|
} catch (Exception e) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void loadTable(Connection conn, String tableName, String[] columns, Path sourceFile) throws Exception { |
||||
|
loadTable(conn, tableName, columns, sourceFile, false); |
||||
|
} |
||||
|
|
||||
|
public static void loadTable(Connection conn, String tableName, String[] columns, Path sourceFile, boolean parseHeader) throws Exception { |
||||
|
CSVFormat csvFormat = CSV_DUMP_FORMAT; |
||||
|
if (parseHeader) { |
||||
|
csvFormat = csvFormat.withFirstRecordAsHeader(); |
||||
|
} else { |
||||
|
csvFormat = CSV_DUMP_FORMAT.withHeader(columns); |
||||
|
} |
||||
|
try (PreparedStatement prepared = conn.prepareStatement(createInsertStatement(tableName, columns))) { |
||||
|
try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(sourceFile), csvFormat)) { |
||||
|
csvParser.forEach(record -> { |
||||
|
try { |
||||
|
for (int i = 0; i < columns.length; i++) { |
||||
|
setColumnValue(i, columns[i], record, prepared); |
||||
|
} |
||||
|
prepared.execute(); |
||||
|
} catch (SQLException e) { |
||||
|
log.error("Unable to load table record!", e); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static void dumpRow(ResultSet res, Map<String, Integer> columnIndexMap, String[] columns, |
||||
|
String[] defaultValues, CSVPrinter csvPrinter) throws Exception { |
||||
|
List<String> record = new ArrayList<>(); |
||||
|
for (int i=0;i<columns.length;i++) { |
||||
|
String column = columns[i]; |
||||
|
String defaultValue; |
||||
|
if (defaultValues != null && i < defaultValues.length) { |
||||
|
defaultValue = defaultValues[i]; |
||||
|
} else { |
||||
|
defaultValue = ""; |
||||
|
} |
||||
|
record.add(getColumnValue(column, defaultValue, columnIndexMap, res)); |
||||
|
} |
||||
|
csvPrinter.printRecord(record); |
||||
|
} |
||||
|
|
||||
|
private static String getColumnValue(String column, String defaultValue, Map<String, Integer> columnIndexMap, ResultSet res) { |
||||
|
int index = columnIndexMap.containsKey(column.toUpperCase()) ? columnIndexMap.get(column.toUpperCase()) : -1; |
||||
|
if (index > -1) { |
||||
|
String str; |
||||
|
try { |
||||
|
Object obj = res.getObject(index); |
||||
|
if (obj == null) { |
||||
|
return null; |
||||
|
} else { |
||||
|
str = obj.toString(); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
str = ""; |
||||
|
} |
||||
|
return str; |
||||
|
} else { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static void setColumnValue(int index, String column, |
||||
|
CSVRecord record, PreparedStatement preparedStatement) throws SQLException { |
||||
|
String value = record.get(column); |
||||
|
int type = preparedStatement.getParameterMetaData().getParameterType(index + 1); |
||||
|
preparedStatement.setObject(index + 1, value, type); |
||||
|
} |
||||
|
|
||||
|
private static String createInsertStatement(String tableName, String[] columns) { |
||||
|
StringBuilder insertStatementBuilder = new StringBuilder(); |
||||
|
insertStatementBuilder.append("INSERT INTO ").append(tableName).append(" ("); |
||||
|
for (String column : columns) { |
||||
|
insertStatementBuilder.append(column).append(","); |
||||
|
} |
||||
|
insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1); |
||||
|
insertStatementBuilder.append(") VALUES ("); |
||||
|
for (String column : columns) { |
||||
|
insertStatementBuilder.append("?").append(","); |
||||
|
} |
||||
|
insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1); |
||||
|
insertStatementBuilder.append(")"); |
||||
|
return insertStatementBuilder.toString(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2017 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
import org.thingsboard.server.common.data.id.CustomerId; |
||||
|
|
||||
|
/** |
||||
|
* Created by igor on 2/27/18. |
||||
|
*/ |
||||
|
|
||||
|
@AllArgsConstructor |
||||
|
public class ShortCustomerInfo { |
||||
|
|
||||
|
@Getter @Setter |
||||
|
private CustomerId customerId; |
||||
|
|
||||
|
@Getter @Setter |
||||
|
private String title; |
||||
|
|
||||
|
@Getter @Setter |
||||
|
private boolean isPublic; |
||||
|
|
||||
|
@Override |
||||
|
public boolean equals(Object o) { |
||||
|
if (this == o) return true; |
||||
|
if (o == null || getClass() != o.getClass()) return false; |
||||
|
|
||||
|
ShortCustomerInfo that = (ShortCustomerInfo) o; |
||||
|
|
||||
|
return customerId.equals(that.customerId); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int hashCode() { |
||||
|
return customerId.hashCode(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2017 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.service; |
||||
|
|
||||
|
import org.thingsboard.server.common.data.id.IdBased; |
||||
|
import org.thingsboard.server.common.data.page.TimePageLink; |
||||
|
|
||||
|
import java.sql.Time; |
||||
|
import java.util.List; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
public abstract class TimePaginatedRemover<I, D extends IdBased<?>> { |
||||
|
|
||||
|
private static final int DEFAULT_LIMIT = 100; |
||||
|
|
||||
|
public void removeEntities(I id) { |
||||
|
TimePageLink pageLink = new TimePageLink(DEFAULT_LIMIT); |
||||
|
boolean hasNext = true; |
||||
|
while (hasNext) { |
||||
|
List<D> entities = findEntities(id, pageLink); |
||||
|
for (D entity : entities) { |
||||
|
removeEntity(entity); |
||||
|
} |
||||
|
hasNext = entities.size() == pageLink.getLimit(); |
||||
|
if (hasNext) { |
||||
|
int index = entities.size() - 1; |
||||
|
UUID idOffset = entities.get(index).getUuidId(); |
||||
|
pageLink.setIdOffset(idOffset); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected abstract List<D> findEntities(I id, TimePageLink pageLink); |
||||
|
|
||||
|
protected abstract void removeEntity(D entity); |
||||
|
|
||||
|
} |
||||
@ -1,123 +0,0 @@ |
|||||
/* |
|
||||
* Copyright © 2016-2017 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 AssignDashboardToCustomerController(customerService, dashboardService, $mdDialog, $q, dashboardIds, 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 dashboardId in dashboardIds) { |
|
||||
tasks.push(dashboardService.assignDashboardToCustomer(vm.customers.selection.id.id, dashboardIds[dashboardId])); |
|
||||
} |
|
||||
$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 |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
@ -1,76 +0,0 @@ |
|||||
<!-- |
|
||||
|
|
||||
Copyright © 2016-2017 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="{{ 'dashboard.assign-dashboard-to-customer' | translate }}"> |
|
||||
<form name="theForm" ng-submit="vm.assign()"> |
|
||||
<md-toolbar> |
|
||||
<div class="md-toolbar-tools"> |
|
||||
<h2 translate>dashboard.assign-dashboard-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>dashboard.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,27 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2017 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
|
||||
|
.tb-dashboard-assigned-customers { |
||||
|
display: block; |
||||
|
display: -webkit-box; |
||||
|
height: 34px; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
-webkit-line-clamp: 2; |
||||
|
-webkit-box-orient: vertical; |
||||
|
margin-bottom: 4px; |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,69 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2017 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 ManageAssignedCustomersController($mdDialog, $q, types, dashboardService, actionType, dashboardIds, assignedCustomers) { |
||||
|
|
||||
|
var vm = this; |
||||
|
|
||||
|
vm.types = types; |
||||
|
vm.actionType = actionType; |
||||
|
vm.dashboardIds = dashboardIds; |
||||
|
vm.assignedCustomers = assignedCustomers; |
||||
|
if (actionType != 'manage') { |
||||
|
vm.assignedCustomers = []; |
||||
|
} |
||||
|
|
||||
|
if (actionType == 'manage') { |
||||
|
vm.titleText = 'dashboard.manage-assigned-customers'; |
||||
|
vm.labelText = 'dashboard.assigned-customers'; |
||||
|
vm.actionName = 'action.update'; |
||||
|
} else if (actionType == 'assign') { |
||||
|
vm.titleText = 'dashboard.assign-to-customers'; |
||||
|
vm.labelText = 'dashboard.assign-to-customers-text'; |
||||
|
vm.actionName = 'action.assign'; |
||||
|
} else if (actionType == 'unassign') { |
||||
|
vm.titleText = 'dashboard.unassign-from-customers'; |
||||
|
vm.labelText = 'dashboard.unassign-from-customers-text'; |
||||
|
vm.actionName = 'action.unassign'; |
||||
|
} |
||||
|
|
||||
|
vm.submit = submit; |
||||
|
vm.cancel = cancel; |
||||
|
|
||||
|
function cancel () { |
||||
|
$mdDialog.cancel(); |
||||
|
} |
||||
|
|
||||
|
function submit () { |
||||
|
var tasks = []; |
||||
|
for (var i=0;i<vm.dashboardIds.length;i++) { |
||||
|
var dashboardId = vm.dashboardIds[i]; |
||||
|
var promise; |
||||
|
if (vm.actionType == 'manage') { |
||||
|
promise = dashboardService.updateDashboardCustomers(dashboardId, vm.assignedCustomers); |
||||
|
} else if (vm.actionType == 'assign') { |
||||
|
promise = dashboardService.addDashboardCustomers(dashboardId, vm.assignedCustomers); |
||||
|
} else if (vm.actionType == 'unassign') { |
||||
|
promise = dashboardService.removeDashboardCustomers(dashboardId, vm.assignedCustomers); |
||||
|
} |
||||
|
tasks.push(promise); |
||||
|
} |
||||
|
$q.all(tasks).then(function () { |
||||
|
$mdDialog.hide(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2017 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="{{ vm.titleText | translate }}" style="width: 600px;"> |
||||
|
<form name="theForm" ng-submit="vm.submit()"> |
||||
|
<md-toolbar> |
||||
|
<div class="md-toolbar-tools"> |
||||
|
<h2 translate>{{vm.titleText}}</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>{{vm.labelText}}</span> |
||||
|
<tb-entity-list ng-disabled="$root.loading" |
||||
|
ng-model="vm.assignedCustomers" |
||||
|
entity-type="vm.types.entityType.customer"></tb-entity-list> |
||||
|
</fieldset> |
||||
|
</div> |
||||
|
</md-dialog-content> |
||||
|
<md-dialog-actions layout="row"> |
||||
|
<span flex></span> |
||||
|
<md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary"> |
||||
|
{{ vm.actionName | 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> |
||||
Loading…
Reference in new issue