Commit 69422fea0e98e1722ee25c1b6503b305c9b7341b

Authored by Volodymyr Babak
2 parents 3898e70c 5f478d9e

Merge branch 'master' of github.com:volodymyr-babak/thingsboard

Showing 100 changed files with 532 additions and 410 deletions

Too many changes to show.

To preserve performance only 100 of 129 files are displayed.

@@ -126,10 +126,6 @@ @@ -126,10 +126,6 @@
126 <artifactId>jjwt</artifactId> 126 <artifactId>jjwt</artifactId>
127 </dependency> 127 </dependency>
128 <dependency> 128 <dependency>
129 - <groupId>joda-time</groupId>  
130 - <artifactId>joda-time</artifactId>  
131 - </dependency>  
132 - <dependency>  
133 <groupId>org.apache.velocity</groupId> 129 <groupId>org.apache.velocity</groupId>
134 <artifactId>velocity</artifactId> 130 <artifactId>velocity</artifactId>
135 </dependency> 131 </dependency>
@@ -112,9 +112,9 @@ @@ -112,9 +112,9 @@
112 "templateHtml": "<tb-timeseries-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-timeseries-table-widget>", 112 "templateHtml": "<tb-timeseries-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-timeseries-table-widget>",
113 "templateCss": "", 113 "templateCss": "",
114 "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('timeseries-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.onDestroy = function() {\n}", 114 "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('timeseries-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.onDestroy = function() {\n}",
115 - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"showTimestamp\"\n ]\n}", 115 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n }\n },\n \"required\": []\n },\n \"form\": [\n \"showTimestamp\",\n \"displayPagination\",\n \"defaultPageSize\"\n ]\n}",
116 "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", 116 "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}",
117 - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":false,\"showLegend\":false}" 117 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{}}"
118 } 118 }
119 } 119 }
120 ] 120 ]
@@ -62,6 +62,7 @@ public final class PluginProcessingContext implements PluginContext { @@ -62,6 +62,7 @@ public final class PluginProcessingContext implements PluginContext {
62 private static final Executor executor = Executors.newSingleThreadExecutor(); 62 private static final Executor executor = Executors.newSingleThreadExecutor();
63 public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!"; 63 public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!";
64 public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!"; 64 public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!";
  65 + public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!";
65 66
66 private final SharedPluginProcessingContext pluginCtx; 67 private final SharedPluginProcessingContext pluginCtx;
67 private final Optional<PluginApiCallSecurityContext> securityCtx; 68 private final Optional<PluginApiCallSecurityContext> securityCtx;
@@ -309,7 +310,7 @@ public final class PluginProcessingContext implements PluginContext { @@ -309,7 +310,7 @@ public final class PluginProcessingContext implements PluginContext {
309 ListenableFuture<Device> deviceFuture = pluginCtx.deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId())); 310 ListenableFuture<Device> deviceFuture = pluginCtx.deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
310 Futures.addCallback(deviceFuture, getCallback(callback, device -> { 311 Futures.addCallback(deviceFuture, getCallback(callback, device -> {
311 if (device == null) { 312 if (device == null) {
312 - return ValidationResult.entityNotFound("Device with requested id wasn't found!"); 313 + return ValidationResult.entityNotFound(DEVICE_WITH_REQUESTED_ID_NOT_FOUND);
313 } else { 314 } else {
314 if (!device.getTenantId().equals(ctx.getTenantId())) { 315 if (!device.getTenantId().equals(ctx.getTenantId())) {
315 return ValidationResult.accessDenied("Device doesn't belong to the current Tenant!"); 316 return ValidationResult.accessDenied("Device doesn't belong to the current Tenant!");
@@ -47,8 +47,8 @@ public class WebSocketConfiguration implements WebSocketConfigurer { @@ -47,8 +47,8 @@ public class WebSocketConfiguration implements WebSocketConfigurer {
47 @Bean 47 @Bean
48 public ServletServerContainerFactoryBean createWebSocketContainer() { 48 public ServletServerContainerFactoryBean createWebSocketContainer() {
49 ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); 49 ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
50 - container.setMaxTextMessageBufferSize(8192);  
51 - container.setMaxBinaryMessageBufferSize(8192); 50 + container.setMaxTextMessageBufferSize(32768);
  51 + container.setMaxBinaryMessageBufferSize(32768);
52 return container; 52 return container;
53 } 53 }
54 54
@@ -82,7 +82,7 @@ public class CustomerController extends BaseController { @@ -82,7 +82,7 @@ public class CustomerController extends BaseController {
82 82
83 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 83 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
84 @RequestMapping(value = "/customer", method = RequestMethod.POST) 84 @RequestMapping(value = "/customer", method = RequestMethod.POST)
85 - @ResponseBody 85 + @ResponseBody
86 public Customer saveCustomer(@RequestBody Customer customer) throws ThingsboardException { 86 public Customer saveCustomer(@RequestBody Customer customer) throws ThingsboardException {
87 try { 87 try {
88 customer.setTenantId(getCurrentUser().getTenantId()); 88 customer.setTenantId(getCurrentUser().getTenantId());
@@ -107,7 +107,7 @@ public class CustomerController extends BaseController { @@ -107,7 +107,7 @@ public class CustomerController extends BaseController {
107 } 107 }
108 108
109 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 109 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
110 - @RequestMapping(value = "/customers", params = { "limit" }, method = RequestMethod.GET) 110 + @RequestMapping(value = "/customers", params = {"limit"}, method = RequestMethod.GET)
111 @ResponseBody 111 @ResponseBody
112 public TextPageData<Customer> getCustomers(@RequestParam int limit, 112 public TextPageData<Customer> getCustomers(@RequestParam int limit,
113 @RequestParam(required = false) String textSearch, 113 @RequestParam(required = false) String textSearch,
@@ -122,4 +122,16 @@ public class CustomerController extends BaseController { @@ -122,4 +122,16 @@ public class CustomerController extends BaseController {
122 } 122 }
123 } 123 }
124 124
  125 + @PreAuthorize("hasAuthority('TENANT_ADMIN')")
  126 + @RequestMapping(value = "/tenant/customers", params = {"customerTitle"}, method = RequestMethod.GET)
  127 + @ResponseBody
  128 + public Customer getTenantCustomer(
  129 + @RequestParam String customerTitle) throws ThingsboardException {
  130 + try {
  131 + TenantId tenantId = getCurrentUser().getTenantId();
  132 + return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle));
  133 + } catch (Exception e) {
  134 + throw handleException(e);
  135 + }
  136 + }
125 } 137 }
@@ -77,7 +77,6 @@ public class PluginWebSocketHandler extends TextWebSocketHandler implements Plug @@ -77,7 +77,6 @@ public class PluginWebSocketHandler extends TextWebSocketHandler implements Plug
77 log.warn("[{}] Failed to find session", session.getId()); 77 log.warn("[{}] Failed to find session", session.getId());
78 session.close(CloseStatus.SERVER_ERROR.withReason("Session not found!")); 78 session.close(CloseStatus.SERVER_ERROR.withReason("Session not found!"));
79 } 79 }
80 - session.sendMessage(message);  
81 } catch (IOException e) { 80 } catch (IOException e) {
82 log.warn("IO error", e); 81 log.warn("IO error", e);
83 } 82 }
@@ -96,7 +96,7 @@ public class DefaultMailService implements MailService { @@ -96,7 +96,7 @@ public class DefaultMailService implements MailService {
96 javaMailProperties.put(MAIL_PROP + protocol + ".port", jsonConfig.get("smtpPort").asText()); 96 javaMailProperties.put(MAIL_PROP + protocol + ".port", jsonConfig.get("smtpPort").asText());
97 javaMailProperties.put(MAIL_PROP + protocol + ".timeout", jsonConfig.get("timeout").asText()); 97 javaMailProperties.put(MAIL_PROP + protocol + ".timeout", jsonConfig.get("timeout").asText());
98 javaMailProperties.put(MAIL_PROP + protocol + ".auth", String.valueOf(StringUtils.isNotEmpty(jsonConfig.get("username").asText()))); 98 javaMailProperties.put(MAIL_PROP + protocol + ".auth", String.valueOf(StringUtils.isNotEmpty(jsonConfig.get("username").asText())));
99 - javaMailProperties.put(MAIL_PROP + protocol + ".starttls.enable", jsonConfig.get("enableTls")); 99 + javaMailProperties.put(MAIL_PROP + protocol + ".starttls.enable", jsonConfig.has("enableTls") ? jsonConfig.get("enableTls").asText() : "false");
100 return javaMailProperties; 100 return javaMailProperties;
101 } 101 }
102 102
@@ -20,7 +20,6 @@ import io.jsonwebtoken.Jws; @@ -20,7 +20,6 @@ import io.jsonwebtoken.Jws;
20 import io.jsonwebtoken.Jwts; 20 import io.jsonwebtoken.Jwts;
21 import io.jsonwebtoken.SignatureAlgorithm; 21 import io.jsonwebtoken.SignatureAlgorithm;
22 import org.apache.commons.lang3.StringUtils; 22 import org.apache.commons.lang3.StringUtils;
23 -import org.joda.time.DateTime;  
24 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.stereotype.Component; 24 import org.springframework.stereotype.Component;
26 import org.thingsboard.server.common.data.id.CustomerId; 25 import org.thingsboard.server.common.data.id.CustomerId;
@@ -31,7 +30,9 @@ import org.thingsboard.server.config.JwtSettings; @@ -31,7 +30,9 @@ import org.thingsboard.server.config.JwtSettings;
31 import org.thingsboard.server.service.security.model.SecurityUser; 30 import org.thingsboard.server.service.security.model.SecurityUser;
32 import org.thingsboard.server.service.security.model.UserPrincipal; 31 import org.thingsboard.server.service.security.model.UserPrincipal;
33 32
34 -import java.util.Arrays; 33 +import java.time.ZonedDateTime;
  34 +import java.util.Collections;
  35 +import java.util.Date;
35 import java.util.List; 36 import java.util.List;
36 import java.util.UUID; 37 import java.util.UUID;
37 import java.util.stream.Collectors; 38 import java.util.stream.Collectors;
@@ -81,13 +82,13 @@ public class JwtTokenFactory { @@ -81,13 +82,13 @@ public class JwtTokenFactory {
81 claims.put(CUSTOMER_ID, securityUser.getCustomerId().getId().toString()); 82 claims.put(CUSTOMER_ID, securityUser.getCustomerId().getId().toString());
82 } 83 }
83 84
84 - DateTime currentTime = new DateTime(); 85 + ZonedDateTime currentTime = ZonedDateTime.now();
85 86
86 String token = Jwts.builder() 87 String token = Jwts.builder()
87 .setClaims(claims) 88 .setClaims(claims)
88 .setIssuer(settings.getTokenIssuer()) 89 .setIssuer(settings.getTokenIssuer())
89 - .setIssuedAt(currentTime.toDate())  
90 - .setExpiration(currentTime.plusSeconds(settings.getTokenExpirationTime()).toDate()) 90 + .setIssuedAt(Date.from(currentTime.toInstant()))
  91 + .setExpiration(Date.from(currentTime.plusSeconds(settings.getTokenExpirationTime()).toInstant()))
91 .signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) 92 .signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey())
92 .compact(); 93 .compact();
93 94
@@ -129,11 +130,11 @@ public class JwtTokenFactory { @@ -129,11 +130,11 @@ public class JwtTokenFactory {
129 throw new IllegalArgumentException("Cannot create JWT Token without username/email"); 130 throw new IllegalArgumentException("Cannot create JWT Token without username/email");
130 } 131 }
131 132
132 - DateTime currentTime = new DateTime(); 133 + ZonedDateTime currentTime = ZonedDateTime.now();
133 134
134 UserPrincipal principal = securityUser.getUserPrincipal(); 135 UserPrincipal principal = securityUser.getUserPrincipal();
135 Claims claims = Jwts.claims().setSubject(principal.getValue()); 136 Claims claims = Jwts.claims().setSubject(principal.getValue());
136 - claims.put(SCOPES, Arrays.asList(Authority.REFRESH_TOKEN.name())); 137 + claims.put(SCOPES, Collections.singletonList(Authority.REFRESH_TOKEN.name()));
137 claims.put(USER_ID, securityUser.getId().getId().toString()); 138 claims.put(USER_ID, securityUser.getId().getId().toString());
138 claims.put(IS_PUBLIC, principal.getType() == UserPrincipal.Type.PUBLIC_ID); 139 claims.put(IS_PUBLIC, principal.getType() == UserPrincipal.Type.PUBLIC_ID);
139 140
@@ -141,8 +142,8 @@ public class JwtTokenFactory { @@ -141,8 +142,8 @@ public class JwtTokenFactory {
141 .setClaims(claims) 142 .setClaims(claims)
142 .setIssuer(settings.getTokenIssuer()) 143 .setIssuer(settings.getTokenIssuer())
143 .setId(UUID.randomUUID().toString()) 144 .setId(UUID.randomUUID().toString())
144 - .setIssuedAt(currentTime.toDate())  
145 - .setExpiration(currentTime.plusSeconds(settings.getRefreshTokenExpTime()).toDate()) 145 + .setIssuedAt(Date.from(currentTime.toInstant()))
  146 + .setExpiration(Date.from(currentTime.plusSeconds(settings.getRefreshTokenExpTime()).toInstant()))
146 .signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) 147 .signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey())
147 .compact(); 148 .compact();
148 149
@@ -107,6 +107,11 @@ public abstract class AbstractControllerTest { @@ -107,6 +107,11 @@ public abstract class AbstractControllerTest {
107 protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org"; 107 protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
108 private static final String CUSTOMER_USER_PASSWORD = "customer"; 108 private static final String CUSTOMER_USER_PASSWORD = "customer";
109 109
  110 + /** See {@link org.springframework.test.web.servlet.DefaultMvcResult#getAsyncResult(long)}
  111 + * and {@link org.springframework.mock.web.MockAsyncContext#getTimeout()}
  112 + */
  113 + private static final long DEFAULT_TIMEOUT = -1L;
  114 +
110 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), 115 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
111 MediaType.APPLICATION_JSON.getSubtype(), 116 MediaType.APPLICATION_JSON.getSubtype(),
112 Charset.forName("utf8")); 117 Charset.forName("utf8"));
@@ -366,7 +371,7 @@ public abstract class AbstractControllerTest { @@ -366,7 +371,7 @@ public abstract class AbstractControllerTest {
366 } 371 }
367 372
368 protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, ResultMatcher resultMatcher, String... params) throws Exception { 373 protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, ResultMatcher resultMatcher, String... params) throws Exception {
369 - return readResponse(doPost(urlTemplate, params).andExpect(resultMatcher), responseClass); 374 + return readResponse(doPost(urlTemplate, content, params).andExpect(resultMatcher), responseClass);
370 } 375 }
371 376
372 protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, String... params) throws Exception { 377 protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, String... params) throws Exception {
@@ -374,7 +379,11 @@ public abstract class AbstractControllerTest { @@ -374,7 +379,11 @@ public abstract class AbstractControllerTest {
374 } 379 }
375 380
376 protected <T> T doPostAsync(String urlTemplate, T content, Class<T> responseClass, ResultMatcher resultMatcher, String... params) throws Exception { 381 protected <T> T doPostAsync(String urlTemplate, T content, Class<T> responseClass, ResultMatcher resultMatcher, String... params) throws Exception {
377 - return readResponse(doPostAsync(urlTemplate, content, params).andExpect(resultMatcher), responseClass); 382 + return readResponse(doPostAsync(urlTemplate, content, DEFAULT_TIMEOUT, params).andExpect(resultMatcher), responseClass);
  383 + }
  384 +
  385 + protected <T> T doPostAsync(String urlTemplate, T content, Class<T> responseClass, ResultMatcher resultMatcher, Long timeout, String... params) throws Exception {
  386 + return readResponse(doPostAsync(urlTemplate, content, timeout, params).andExpect(resultMatcher), responseClass);
378 } 387 }
379 388
380 protected <T> T doDelete(String urlTemplate, Class<T> responseClass, String... params) throws Exception { 389 protected <T> T doDelete(String urlTemplate, Class<T> responseClass, String... params) throws Exception {
@@ -396,12 +405,13 @@ public abstract class AbstractControllerTest { @@ -396,12 +405,13 @@ public abstract class AbstractControllerTest {
396 return mockMvc.perform(postRequest); 405 return mockMvc.perform(postRequest);
397 } 406 }
398 407
399 - protected <T> ResultActions doPostAsync(String urlTemplate, T content, String... params) throws Exception { 408 + protected <T> ResultActions doPostAsync(String urlTemplate, T content, Long timeout, String... params) throws Exception {
400 MockHttpServletRequestBuilder postRequest = post(urlTemplate); 409 MockHttpServletRequestBuilder postRequest = post(urlTemplate);
401 setJwtToken(postRequest); 410 setJwtToken(postRequest);
402 String json = json(content); 411 String json = json(content);
403 postRequest.contentType(contentType).content(json); 412 postRequest.contentType(contentType).content(json);
404 MvcResult result = mockMvc.perform(postRequest).andReturn(); 413 MvcResult result = mockMvc.perform(postRequest).andReturn();
  414 + result.getAsyncResult(timeout);
405 return mockMvc.perform(asyncDispatch(result)); 415 return mockMvc.perform(asyncDispatch(result));
406 } 416 }
407 417
@@ -414,8 +424,8 @@ public abstract class AbstractControllerTest { @@ -414,8 +424,8 @@ public abstract class AbstractControllerTest {
414 424
415 protected void populateParams(MockHttpServletRequestBuilder request, String... params) { 425 protected void populateParams(MockHttpServletRequestBuilder request, String... params) {
416 if (params != null && params.length > 0) { 426 if (params != null && params.length > 0) {
417 - Assert.assertEquals(params.length % 2, 0);  
418 - MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<String, String>(); 427 + Assert.assertEquals(0, params.length % 2);
  428 + MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
419 for (int i = 0; i < params.length; i += 2) { 429 for (int i = 0; i < params.length; i += 2) {
420 paramsMap.add(params[i], params[i + 1]); 430 paramsMap.add(params[i], params[i + 1]);
421 } 431 }
@@ -15,21 +15,23 @@ @@ -15,21 +15,23 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.rpc; 16 package org.thingsboard.server.mqtt.rpc;
17 17
  18 +import java.util.Arrays;
  19 +
  20 +import com.datastax.driver.core.utils.UUIDs;
  21 +import com.fasterxml.jackson.core.type.TypeReference;
18 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
19 import org.apache.commons.lang3.StringUtils; 23 import org.apache.commons.lang3.StringUtils;
20 import org.eclipse.paho.client.mqttv3.*; 24 import org.eclipse.paho.client.mqttv3.*;
21 import org.junit.*; 25 import org.junit.*;
22 -import org.springframework.http.HttpStatus;  
23 -import org.springframework.web.client.HttpClientErrorException; 26 +import org.thingsboard.server.actors.plugin.PluginProcessingContext;
24 import org.thingsboard.server.common.data.Device; 27 import org.thingsboard.server.common.data.Device;
25 import org.thingsboard.server.common.data.Tenant; 28 import org.thingsboard.server.common.data.Tenant;
26 import org.thingsboard.server.common.data.User; 29 import org.thingsboard.server.common.data.User;
  30 +import org.thingsboard.server.common.data.page.TextPageData;
  31 +import org.thingsboard.server.common.data.plugin.PluginMetaData;
27 import org.thingsboard.server.common.data.security.Authority; 32 import org.thingsboard.server.common.data.security.Authority;
28 import org.thingsboard.server.common.data.security.DeviceCredentials; 33 import org.thingsboard.server.common.data.security.DeviceCredentials;
29 import org.thingsboard.server.controller.AbstractControllerTest; 34 import org.thingsboard.server.controller.AbstractControllerTest;
30 -import org.thingsboard.server.dao.service.DaoNoSqlTest;  
31 -  
32 -import java.util.UUID;  
33 35
34 import static org.junit.Assert.assertEquals; 36 import static org.junit.Assert.assertEquals;
35 import static org.junit.Assert.assertNotNull; 37 import static org.junit.Assert.assertNotNull;
@@ -42,15 +44,19 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @@ -42,15 +44,19 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
42 public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractControllerTest { 44 public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractControllerTest {
43 45
44 private static final String MQTT_URL = "tcp://localhost:1883"; 46 private static final String MQTT_URL = "tcp://localhost:1883";
45 - private static final String FAIL_MSG_IF_HTTP_CLIENT_ERROR_NOT_ENCOUNTERED = "HttpClientErrorException expected, but not encountered"; 47 + private static final Long TIME_TO_HANDLE_REQUEST = 500L;
46 48
47 private Tenant savedTenant; 49 private Tenant savedTenant;
48 private User tenantAdmin; 50 private User tenantAdmin;
  51 + private Long asyncContextTimeoutToUseRpcPlugin;
  52 +
49 53
50 @Before 54 @Before
51 public void beforeTest() throws Exception { 55 public void beforeTest() throws Exception {
52 loginSysAdmin(); 56 loginSysAdmin();
53 57
  58 + asyncContextTimeoutToUseRpcPlugin = getAsyncContextTimeoutToUseRpcPlugin();
  59 +
54 Tenant tenant = new Tenant(); 60 Tenant tenant = new Tenant();
55 tenant.setTitle("My tenant"); 61 tenant.setTitle("My tenant");
56 savedTenant = doPost("/api/tenant", tenant, Tenant.class); 62 savedTenant = doPost("/api/tenant", tenant, Tenant.class);
@@ -70,8 +76,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -70,8 +76,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
70 public void afterTest() throws Exception { 76 public void afterTest() throws Exception {
71 loginSysAdmin(); 77 loginSysAdmin();
72 if (savedTenant != null) { 78 if (savedTenant != null) {
73 - doDelete("/api/tenant/" + savedTenant.getId().getId().toString())  
74 - .andExpect(status().isOk()); 79 + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk());
75 } 80 }
76 } 81 }
77 82
@@ -102,7 +107,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -102,7 +107,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
102 } 107 }
103 108
104 @Test 109 @Test
105 - @Ignore // TODO: figure out the right error code for this case. Ignored due to failure: expected 408 but was: 200  
106 public void testServerMqttOneWayRpcDeviceOffline() throws Exception { 110 public void testServerMqttOneWayRpcDeviceOffline() throws Exception {
107 Device device = new Device(); 111 Device device = new Device();
108 device.setName("Test One-Way Server-Side RPC Device Offline"); 112 device.setName("Test One-Way Server-Side RPC Device Offline");
@@ -115,29 +119,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -115,29 +119,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
115 119
116 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; 120 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
117 String deviceId = savedDevice.getId().getId().toString(); 121 String deviceId = savedDevice.getId().getId().toString();
118 - try {  
119 - doPost("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(408));  
120 - Assert.fail(FAIL_MSG_IF_HTTP_CLIENT_ERROR_NOT_ENCOUNTERED);  
121 - } catch (HttpClientErrorException e) {  
122 - log.error(e.getMessage(), e);  
123 - Assert.assertEquals(HttpStatus.REQUEST_TIMEOUT, e.getStatusCode());  
124 - Assert.assertEquals("408 null", e.getMessage());  
125 - } 122 +
  123 + doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isRequestTimeout(),
  124 + asyncContextTimeoutToUseRpcPlugin);
126 } 125 }
127 126
128 @Test 127 @Test
129 - @Ignore // TODO: figure out the right error code for this case. Ignored due to failure: expected 400 (404?) but was: 401  
130 public void testServerMqttOneWayRpcDeviceDoesNotExist() throws Exception { 128 public void testServerMqttOneWayRpcDeviceDoesNotExist() throws Exception {
131 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; 129 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
132 - String nonExistentDeviceId = UUID.randomUUID().toString();  
133 - try {  
134 - doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class, status().is(400));  
135 - Assert.fail(FAIL_MSG_IF_HTTP_CLIENT_ERROR_NOT_ENCOUNTERED);  
136 - } catch (HttpClientErrorException e) {  
137 - log.error(e.getMessage(), e);  
138 - Assert.assertEquals(HttpStatus.BAD_REQUEST, e.getStatusCode());  
139 - Assert.assertEquals("400 null", e.getMessage());  
140 - } 130 + String nonExistentDeviceId = UUIDs.timeBased().toString();
  131 +
  132 + String result = doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class,
  133 + status().isNotFound());
  134 + Assert.assertEquals(PluginProcessingContext.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
141 } 135 }
142 136
143 @Test 137 @Test
@@ -168,7 +162,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -168,7 +162,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
168 } 162 }
169 163
170 @Test 164 @Test
171 - @Ignore // TODO: figure out the right error code for this case. Ignored due to failure: expected 408 but was: 200  
172 public void testServerMqttTwoWayRpcDeviceOffline() throws Exception { 165 public void testServerMqttTwoWayRpcDeviceOffline() throws Exception {
173 Device device = new Device(); 166 Device device = new Device();
174 device.setName("Test Two-Way Server-Side RPC Device Offline"); 167 device.setName("Test Two-Way Server-Side RPC Device Offline");
@@ -181,29 +174,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -181,29 +174,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
181 174
182 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; 175 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
183 String deviceId = savedDevice.getId().getId().toString(); 176 String deviceId = savedDevice.getId().getId().toString();
184 - try {  
185 - doPost("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(408));  
186 - Assert.fail(FAIL_MSG_IF_HTTP_CLIENT_ERROR_NOT_ENCOUNTERED);  
187 - } catch (HttpClientErrorException e) {  
188 - log.error(e.getMessage(), e);  
189 - Assert.assertEquals(HttpStatus.REQUEST_TIMEOUT, e.getStatusCode());  
190 - Assert.assertEquals("408 null", e.getMessage());  
191 - } 177 +
  178 + doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isRequestTimeout(),
  179 + asyncContextTimeoutToUseRpcPlugin);
192 } 180 }
193 181
194 @Test 182 @Test
195 - @Ignore // TODO: figure out the right error code for this case. Ignored due to failure: expected 400 (404?) but was: 401  
196 public void testServerMqttTwoWayRpcDeviceDoesNotExist() throws Exception { 183 public void testServerMqttTwoWayRpcDeviceDoesNotExist() throws Exception {
197 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; 184 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
198 - String nonExistentDeviceId = UUID.randomUUID().toString();  
199 - try {  
200 - doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class, status().is(400));  
201 - Assert.fail(FAIL_MSG_IF_HTTP_CLIENT_ERROR_NOT_ENCOUNTERED);  
202 - } catch (HttpClientErrorException e) {  
203 - log.error(e.getMessage(), e);  
204 - Assert.assertEquals(HttpStatus.BAD_REQUEST, e.getStatusCode());  
205 - Assert.assertEquals("400 null", e.getMessage());  
206 - } 185 + String nonExistentDeviceId = UUIDs.timeBased().toString();
  186 +
  187 + String result = doPostAsync("/api/plugins/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class,
  188 + status().isNotFound());
  189 + Assert.assertEquals(PluginProcessingContext.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
207 } 190 }
208 191
209 private Device getSavedDevice(Device device) throws Exception { 192 private Device getSavedDevice(Device device) throws Exception {
@@ -214,6 +197,13 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -214,6 +197,13 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
214 return doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 197 return doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
215 } 198 }
216 199
  200 + private Long getAsyncContextTimeoutToUseRpcPlugin() throws Exception {
  201 + TextPageData<PluginMetaData> plugins = doGetTyped("/api/plugin/system?limit=1&textSearch=system rpc plugin",
  202 + new TypeReference<TextPageData<PluginMetaData>>(){});
  203 + Long systemRpcPluginTimeout = plugins.getData().iterator().next().getConfiguration().get("defaultTimeout").asLong();
  204 + return systemRpcPluginTimeout + TIME_TO_HANDLE_REQUEST;
  205 + }
  206 +
217 private static class TestMqttCallback implements MqttCallback { 207 private static class TestMqttCallback implements MqttCallback {
218 208
219 private final MqttAsyncClient client; 209 private final MqttAsyncClient client;
@@ -228,10 +218,10 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -228,10 +218,10 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
228 218
229 @Override 219 @Override
230 public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception { 220 public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception {
231 - log.info("Message Arrived: " + mqttMessage.getPayload().toString()); 221 + log.info("Message Arrived: " + Arrays.toString(mqttMessage.getPayload()));
232 MqttMessage message = new MqttMessage(); 222 MqttMessage message = new MqttMessage();
233 String responseTopic = requestTopic.replace("request", "response"); 223 String responseTopic = requestTopic.replace("request", "response");
234 - message.setPayload("{\"value1\":\"A\", \"value2\":\"B\"}".getBytes()); 224 + message.setPayload("{\"value1\":\"A\", \"value2\":\"B\"}".getBytes("UTF-8"));
235 client.publish(responseTopic, message); 225 client.publish(responseTopic, message);
236 } 226 }
237 227
@@ -22,20 +22,24 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -22,20 +22,24 @@ import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.data.page.TextPageData; 22 import org.thingsboard.server.common.data.page.TextPageData;
23 import org.thingsboard.server.common.data.page.TextPageLink; 23 import org.thingsboard.server.common.data.page.TextPageLink;
24 24
  25 +import java.util.Optional;
  26 +
25 public interface CustomerService { 27 public interface CustomerService {
26 28
27 Customer findCustomerById(CustomerId customerId); 29 Customer findCustomerById(CustomerId customerId);
28 30
  31 + Optional<Customer> findCustomerByTenantIdAndTitle(TenantId tenantId, String title);
  32 +
29 ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId); 33 ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId);
30 34
31 Customer saveCustomer(Customer customer); 35 Customer saveCustomer(Customer customer);
32 - 36 +
33 void deleteCustomer(CustomerId customerId); 37 void deleteCustomer(CustomerId customerId);
34 38
35 Customer findOrCreatePublicCustomer(TenantId tenantId); 39 Customer findOrCreatePublicCustomer(TenantId tenantId);
36 40
37 TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink); 41 TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink);
38 - 42 +
39 void deleteCustomersByTenantId(TenantId tenantId); 43 void deleteCustomersByTenantId(TenantId tenantId);
40 44
41 } 45 }
@@ -52,6 +52,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @@ -52,6 +52,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
52 52
53 private static final String PUBLIC_CUSTOMER_TITLE = "Public"; 53 private static final String PUBLIC_CUSTOMER_TITLE = "Public";
54 public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; 54 public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
  55 + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
55 56
56 @Autowired 57 @Autowired
57 private CustomerDao customerDao; 58 private CustomerDao customerDao;
@@ -79,6 +80,13 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @@ -79,6 +80,13 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
79 } 80 }
80 81
81 @Override 82 @Override
  83 + public Optional<Customer> findCustomerByTenantIdAndTitle(TenantId tenantId, String title) {
  84 + log.trace("Executing findCustomerByTenantIdAndTitle [{}] [{}]", tenantId, title);
  85 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  86 + return customerDao.findCustomersByTenantIdAndTitle(tenantId.getId(), title);
  87 + }
  88 +
  89 + @Override
82 public ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId) { 90 public ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId) {
83 log.trace("Executing findCustomerByIdAsync [{}]", customerId); 91 log.trace("Executing findCustomerByIdAsync [{}]", customerId);
84 validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); 92 validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 <spring.version>4.3.4.RELEASE</spring.version> 33 <spring.version>4.3.4.RELEASE</spring.version>
34 <spring-security.version>4.2.0.RELEASE</spring-security.version> 34 <spring-security.version>4.2.0.RELEASE</spring-security.version>
35 <jjwt.version>0.7.0</jjwt.version> 35 <jjwt.version>0.7.0</jjwt.version>
36 - <joda-time.version>2.4</joda-time.version>  
37 - <json-path.version>2.2.0</json-path.version> 36 + <json-path.version>2.2.0</json-path.version>
38 <junit.version>4.12</junit.version> 37 <junit.version>4.12</junit.version>
39 <slf4j.version>1.7.7</slf4j.version> 38 <slf4j.version>1.7.7</slf4j.version>
40 <logback.version>1.2.3</logback.version> 39 <logback.version>1.2.3</logback.version>
@@ -484,11 +483,6 @@ @@ -484,11 +483,6 @@
484 <version>${jjwt.version}</version> 483 <version>${jjwt.version}</version>
485 </dependency> 484 </dependency>
486 <dependency> 485 <dependency>
487 - <groupId>joda-time</groupId>  
488 - <artifactId>joda-time</artifactId>  
489 - <version>${joda-time.version}</version>  
490 - </dependency>  
491 - <dependency>  
492 <groupId>org.apache.velocity</groupId> 486 <groupId>org.apache.velocity</groupId>
493 <artifactId>velocity</artifactId> 487 <artifactId>velocity</artifactId>
494 <version>${velocity.version}</version> 488 <version>${velocity.version}</version>
@@ -29,13 +29,12 @@ import org.springframework.web.client.RestTemplate; @@ -29,13 +29,12 @@ import org.springframework.web.client.RestTemplate;
29 import org.thingsboard.server.common.data.Customer; 29 import org.thingsboard.server.common.data.Customer;
30 import org.thingsboard.server.common.data.Device; 30 import org.thingsboard.server.common.data.Device;
31 import org.thingsboard.server.common.data.alarm.Alarm; 31 import org.thingsboard.server.common.data.alarm.Alarm;
32 -import org.thingsboard.server.common.data.alarm.AlarmSeverity;  
33 -import org.thingsboard.server.common.data.alarm.AlarmStatus;  
34 import org.thingsboard.server.common.data.asset.Asset; 32 import org.thingsboard.server.common.data.asset.Asset;
35 import org.thingsboard.server.common.data.id.AssetId; 33 import org.thingsboard.server.common.data.id.AssetId;
36 import org.thingsboard.server.common.data.id.CustomerId; 34 import org.thingsboard.server.common.data.id.CustomerId;
37 import org.thingsboard.server.common.data.id.DeviceId; 35 import org.thingsboard.server.common.data.id.DeviceId;
38 import org.thingsboard.server.common.data.id.EntityId; 36 import org.thingsboard.server.common.data.id.EntityId;
  37 +import org.thingsboard.server.common.data.relation.EntityRelation;
39 import org.thingsboard.server.common.data.security.DeviceCredentials; 38 import org.thingsboard.server.common.data.security.DeviceCredentials;
40 39
41 import java.io.IOException; 40 import java.io.IOException;
@@ -78,6 +77,36 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -78,6 +77,36 @@ public class RestClient implements ClientHttpRequestInterceptor {
78 } 77 }
79 } 78 }
80 79
  80 + public Optional<Customer> findCustomer(String title) {
  81 + Map<String, String> params = new HashMap<String, String>();
  82 + params.put("customerTitle", title);
  83 + try {
  84 + ResponseEntity<Customer> customerEntity = restTemplate.getForEntity(baseURL + "/api/tenant/customers?customerTitle={customerTitle}", Customer.class, params);
  85 + return Optional.of(customerEntity.getBody());
  86 + } catch (HttpClientErrorException exception) {
  87 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  88 + return Optional.empty();
  89 + } else {
  90 + throw exception;
  91 + }
  92 + }
  93 + }
  94 +
  95 + public Optional<Asset> findAsset(String name) {
  96 + Map<String, String> params = new HashMap<String, String>();
  97 + params.put("assetName", name);
  98 + try {
  99 + ResponseEntity<Asset> assetEntity = restTemplate.getForEntity(baseURL + "/api/tenant/assets?assetName={assetName}", Asset.class, params);
  100 + return Optional.of(assetEntity.getBody());
  101 + } catch (HttpClientErrorException exception) {
  102 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  103 + return Optional.empty();
  104 + } else {
  105 + throw exception;
  106 + }
  107 + }
  108 + }
  109 +
81 public Customer createCustomer(String title) { 110 public Customer createCustomer(String title) {
82 Customer customer = new Customer(); 111 Customer customer = new Customer();
83 customer.setTitle(title); 112 customer.setTitle(title);
@@ -112,6 +141,14 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -112,6 +141,14 @@ public class RestClient implements ClientHttpRequestInterceptor {
112 customerId.toString(), assetId.toString()).getBody(); 141 customerId.toString(), assetId.toString()).getBody();
113 } 142 }
114 143
  144 + public EntityRelation makeRelation(String relationType, EntityId idFrom, EntityId idTo) {
  145 + EntityRelation relation = new EntityRelation();
  146 + relation.setFrom(idFrom);
  147 + relation.setTo(idTo);
  148 + relation.setType(relationType);
  149 + return restTemplate.postForEntity(baseURL + "/api/relation", relation, EntityRelation.class).getBody();
  150 + }
  151 +
115 public DeviceCredentials getCredentials(DeviceId id) { 152 public DeviceCredentials getCredentials(DeviceId id) {
116 return restTemplate.getForEntity(baseURL + "/api/device/" + id.getId().toString() + "/credentials", DeviceCredentials.class).getBody(); 153 return restTemplate.getForEntity(baseURL + "/api/device/" + id.getId().toString() + "/credentials", DeviceCredentials.class).getBody();
117 } 154 }
@@ -74,13 +74,13 @@ echo "Generating SSL Key Pair..." @@ -74,13 +74,13 @@ echo "Generating SSL Key Pair..."
74 74
75 keytool -genkeypair -v \ 75 keytool -genkeypair -v \
76 -alias $CLIENT_KEY_ALIAS \ 76 -alias $CLIENT_KEY_ALIAS \
77 - -dname "CN=$DOMAIN_SUFFIX, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \  
78 -keystore $CLIENT_FILE_PREFIX.jks \ 77 -keystore $CLIENT_FILE_PREFIX.jks \
79 -keypass $CLIENT_KEY_PASSWORD \ 78 -keypass $CLIENT_KEY_PASSWORD \
80 -storepass $CLIENT_KEYSTORE_PASSWORD \ 79 -storepass $CLIENT_KEYSTORE_PASSWORD \
81 -keyalg RSA \ 80 -keyalg RSA \
82 -keysize 2048 \ 81 -keysize 2048 \
83 - -validity 9999 82 + -validity 9999 \
  83 + -dname "CN=$DOMAIN_SUFFIX, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE"
84 84
85 echo "Converting keystore to pkcs12" 85 echo "Converting keystore to pkcs12"
86 keytool -importkeystore \ 86 keytool -importkeystore \
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 DOMAIN_SUFFIX="$(hostname)" 17 DOMAIN_SUFFIX="$(hostname)"
18 ORGANIZATIONAL_UNIT=Thingsboard 18 ORGANIZATIONAL_UNIT=Thingsboard
19 ORGANIZATION=Thingsboard 19 ORGANIZATION=Thingsboard
20 -CITY=San Francisco 20 +CITY=SF
21 STATE_OR_PROVINCE=CA 21 STATE_OR_PROVINCE=CA
22 TWO_LETTER_COUNTRY_CODE=US 22 TWO_LETTER_COUNTRY_CODE=US
23 23
@@ -22,11 +22,11 @@ @@ -22,11 +22,11 @@
22 <span translate class="md-headline">admin.general-settings</span> 22 <span translate class="md-headline">admin.general-settings</span>
23 </md-card-title-text> 23 </md-card-title-text>
24 </md-card-title> 24 </md-card-title>
25 - <md-progress-linear md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
26 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 25 + <md-progress-linear md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  26 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
27 <md-card-content> 27 <md-card-content>
28 <form name="vm.settingsForm" ng-submit="vm.save()" tb-confirm-on-exit confirm-form="vm.settingsForm"> 28 <form name="vm.settingsForm" ng-submit="vm.save()" tb-confirm-on-exit confirm-form="vm.settingsForm">
29 - <fieldset ng-disabled="loading"> 29 + <fieldset ng-disabled="$root.loading">
30 <md-input-container class="md-block"> 30 <md-input-container class="md-block">
31 <label translate>admin.base-url</label> 31 <label translate>admin.base-url</label>
32 <input required name="baseUrl" ng-model="vm.settings.jsonValue.baseUrl"> 32 <input required name="baseUrl" ng-model="vm.settings.jsonValue.baseUrl">
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 </div> 35 </div>
36 </md-input-container> 36 </md-input-container>
37 <div layout="row" layout-align="end center" width="100%" layout-wrap> 37 <div layout="row" layout-align="end center" width="100%" layout-wrap>
38 - <md-button ng-disabled="loading || vm.settingsForm.$invalid || !vm.settingsForm.$dirty" type="submit" class="md-raised md-primary">{{'action.save' | translate}}</md-button> 38 + <md-button ng-disabled="$root.loading || vm.settingsForm.$invalid || !vm.settingsForm.$dirty" type="submit" class="md-raised md-primary">{{'action.save' | translate}}</md-button>
39 </div> 39 </div>
40 </fieldset> 40 </fieldset>
41 </form> 41 </form>
@@ -24,11 +24,11 @@ @@ -24,11 +24,11 @@
24 <div id="help-container"></div> 24 <div id="help-container"></div>
25 </md-card-title-text> 25 </md-card-title-text>
26 </md-card-title> 26 </md-card-title>
27 - <md-progress-linear md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
28 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 27 + <md-progress-linear md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  28 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
29 <md-card-content> 29 <md-card-content>
30 <form name="vm.settingsForm" ng-submit="vm.save()" tb-confirm-on-exit confirm-form="vm.settingsForm"> 30 <form name="vm.settingsForm" ng-submit="vm.save()" tb-confirm-on-exit confirm-form="vm.settingsForm">
31 - <fieldset ng-disabled="loading"> 31 + <fieldset ng-disabled="$root.loading">
32 <md-input-container class="md-block"> 32 <md-input-container class="md-block">
33 <label translate>admin.mail-from</label> 33 <label translate>admin.mail-from</label>
34 <input required name="mailFrom" ng-model="vm.settings.jsonValue.mailFrom"> 34 <input required name="mailFrom" ng-model="vm.settings.jsonValue.mailFrom">
@@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
38 </md-input-container> 38 </md-input-container>
39 <md-input-container class="md-block"> 39 <md-input-container class="md-block">
40 <label translate>admin.smtp-protocol</label> 40 <label translate>admin.smtp-protocol</label>
41 - <md-select ng-disabled="loading" ng-model="vm.settings.jsonValue.smtpProtocol"> 41 + <md-select ng-disabled="$root.loading" ng-model="vm.settings.jsonValue.smtpProtocol">
42 <md-option ng-repeat="smtpProtocol in vm.smtpProtocols" value="{{smtpProtocol}}"> 42 <md-option ng-repeat="smtpProtocol in vm.smtpProtocols" value="{{smtpProtocol}}">
43 {{smtpProtocol.toUpperCase()}} 43 {{smtpProtocol.toUpperCase()}}
44 </md-option> 44 </md-option>
@@ -78,7 +78,7 @@ @@ -78,7 +78,7 @@
78 <div translate ng-message="md-maxlength">admin.timeout-invalid</div> 78 <div translate ng-message="md-maxlength">admin.timeout-invalid</div>
79 </div> 79 </div>
80 </md-input-container> 80 </md-input-container>
81 - <md-checkbox ng-disabled="loading" ng-true-value="'true'" ng-false-value="'false'" 81 + <md-checkbox ng-disabled="$root.loading" ng-true-value="'true'" ng-false-value="'false'"
82 aria-label="{{ 'admin.enable-tls' | translate }}" ng-model="vm.settings.jsonValue.enableTls">{{ 'admin.enable-tls' | translate }}</md-checkbox> 82 aria-label="{{ 'admin.enable-tls' | translate }}" ng-model="vm.settings.jsonValue.enableTls">{{ 'admin.enable-tls' | translate }}</md-checkbox>
83 <md-input-container class="md-block"> 83 <md-input-container class="md-block">
84 <label translate>common.username</label> 84 <label translate>common.username</label>
@@ -89,8 +89,8 @@ @@ -89,8 +89,8 @@
89 <input name="password" placeholder="{{ 'common.enter-password' | translate }}" type="password" ng-model="vm.settings.jsonValue.password"> 89 <input name="password" placeholder="{{ 'common.enter-password' | translate }}" type="password" ng-model="vm.settings.jsonValue.password">
90 </md-input-container> 90 </md-input-container>
91 <div layout="row" layout-align="end center" width="100%" layout-wrap> 91 <div layout="row" layout-align="end center" width="100%" layout-wrap>
92 - <md-button ng-disabled="loading || vm.settingsForm.$invalid" ng-click="vm.sendTestMail()" class="md-raised">{{'admin.send-test-mail' | translate}}</md-button>  
93 - <md-button ng-disabled="loading || vm.settingsForm.$invalid || !vm.settingsForm.$dirty" type="submit" class="md-raised md-primary">{{'action.save' | translate}}</md-button> 92 + <md-button ng-disabled="$root.loading || vm.settingsForm.$invalid" ng-click="vm.sendTestMail()" class="md-raised">{{'admin.send-test-mail' | translate}}</md-button>
  93 + <md-button ng-disabled="$root.loading || vm.settingsForm.$invalid || !vm.settingsForm.$dirty" type="submit" class="md-raised md-primary">{{'action.save' | translate}}</md-button>
94 </div> 94 </div>
95 </fieldset> 95 </fieldset>
96 </form> 96 </form>
@@ -87,7 +87,7 @@ @@ -87,7 +87,7 @@
87 <md-button ng-if="vm.allowAcknowledgment && (vm.alarm.status==vm.types.alarmStatus.activeUnack || 87 <md-button ng-if="vm.allowAcknowledgment && (vm.alarm.status==vm.types.alarmStatus.activeUnack ||
88 vm.alarm.status==vm.types.alarmStatus.clearedUnack)" 88 vm.alarm.status==vm.types.alarmStatus.clearedUnack)"
89 class="md-raised md-primary" 89 class="md-raised md-primary"
90 - ng-disabled="loading" 90 + ng-disabled="$root.loading"
91 ng-click="vm.acknowledge()" 91 ng-click="vm.acknowledge()"
92 style="margin-right:20px;">{{ 'alarm.acknowledge' | 92 style="margin-right:20px;">{{ 'alarm.acknowledge' |
93 translate }} 93 translate }}
@@ -95,12 +95,12 @@ @@ -95,12 +95,12 @@
95 <md-button ng-if="vm.allowClear && (vm.alarm.status==vm.types.alarmStatus.activeAck || 95 <md-button ng-if="vm.allowClear && (vm.alarm.status==vm.types.alarmStatus.activeAck ||
96 vm.alarm.status==vm.types.alarmStatus.activeUnack)" 96 vm.alarm.status==vm.types.alarmStatus.activeUnack)"
97 class="md-raised md-primary" 97 class="md-raised md-primary"
98 - ng-disabled="loading" 98 + ng-disabled="$root.loading"
99 ng-click="vm.clear()">{{ 'alarm.clear' | 99 ng-click="vm.clear()">{{ 'alarm.clear' |
100 translate }} 100 translate }}
101 </md-button> 101 </md-button>
102 <span flex></span> 102 <span flex></span>
103 - <md-button ng-disabled="loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' | 103 + <md-button ng-disabled="$root.loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' |
104 translate }} 104 translate }}
105 </md-button> 105 </md-button>
106 </md-dialog-actions> 106 </md-dialog-actions>
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 <section layout="row"> 19 <section layout="row">
20 <md-input-container class="md-block" style="width: 200px;"> 20 <md-input-container class="md-block" style="width: 200px;">
21 <label translate>alarm.alarm-status</label> 21 <label translate>alarm.alarm-status</label>
22 - <md-select ng-model="alarmSearchStatus" ng-disabled="loading()"> 22 + <md-select ng-model="alarmSearchStatus" ng-disabled="$root.loading">
23 <md-option ng-repeat="searchStatus in types.alarmSearchStatus" ng-value="searchStatus"> 23 <md-option ng-repeat="searchStatus in types.alarmSearchStatus" ng-value="searchStatus">
24 {{ ('alarm.search-status.' + searchStatus) | translate }} 24 {{ ('alarm.search-status.' + searchStatus) | translate }}
25 </md-option> 25 </md-option>
@@ -31,8 +31,8 @@ @@ -31,8 +31,8 @@
31 <md-list flex layout="column" class="tb-alarm-table"> 31 <md-list flex layout="column" class="tb-alarm-table">
32 <md-list class="tb-row tb-header" layout="row" tb-alarm-header> 32 <md-list class="tb-row tb-header" layout="row" tb-alarm-header>
33 </md-list> 33 </md-list>
34 - <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!loading()"  
35 - ng-show="loading()"></md-progress-linear> 34 + <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!$root.loading"
  35 + ng-show="$root.loading"></md-progress-linear>
36 <md-divider></md-divider> 36 <md-divider></md-divider>
37 <span translate layout-align="center center" 37 <span translate layout-align="center center"
38 style="margin-top: 25px;" 38 style="margin-top: 25px;"
@@ -265,10 +265,10 @@ function AssetService($http, $q, customerService, userService) { @@ -265,10 +265,10 @@ function AssetService($http, $q, customerService, userService) {
265 return deferred.promise; 265 return deferred.promise;
266 } 266 }
267 267
268 - function getAssetTypes() { 268 + function getAssetTypes(config) {
269 var deferred = $q.defer(); 269 var deferred = $q.defer();
270 var url = '/api/asset/types'; 270 var url = '/api/asset/types';
271 - $http.get(url).then(function success(response) { 271 + $http.get(url, config).then(function success(response) {
272 deferred.resolve(response.data); 272 deferred.resolve(response.data);
273 }, function fail() { 273 }, function fail() {
274 deferred.reject(); 274 deferred.reject();
@@ -35,7 +35,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) @@ -35,7 +35,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
35 35
36 return service; 36 return service;
37 37
38 - function getEntityKeys(entityType, entityId, query, type) { 38 + function getEntityKeys(entityType, entityId, query, type, config) {
39 var deferred = $q.defer(); 39 var deferred = $q.defer();
40 var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; 40 var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/';
41 if (type === types.dataKeyType.timeseries) { 41 if (type === types.dataKeyType.timeseries) {
@@ -43,7 +43,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) @@ -43,7 +43,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
43 } else if (type === types.dataKeyType.attribute) { 43 } else if (type === types.dataKeyType.attribute) {
44 url += 'attributes'; 44 url += 'attributes';
45 } 45 }
46 - $http.get(url, null).then(function success(response) { 46 + $http.get(url, config).then(function success(response) {
47 var result = []; 47 var result = [];
48 if (response.data) { 48 if (response.data) {
49 if (query) { 49 if (query) {
@@ -32,7 +32,7 @@ function CustomerService($http, $q, types) { @@ -32,7 +32,7 @@ function CustomerService($http, $q, types) {
32 32
33 return service; 33 return service;
34 34
35 - function getCustomers(pageLink) { 35 + function getCustomers(pageLink, config) {
36 var deferred = $q.defer(); 36 var deferred = $q.defer();
37 var url = '/api/customers?limit=' + pageLink.limit; 37 var url = '/api/customers?limit=' + pageLink.limit;
38 if (angular.isDefined(pageLink.textSearch)) { 38 if (angular.isDefined(pageLink.textSearch)) {
@@ -44,7 +44,7 @@ function CustomerService($http, $q, types) { @@ -44,7 +44,7 @@ function CustomerService($http, $q, types) {
44 if (angular.isDefined(pageLink.textOffset)) { 44 if (angular.isDefined(pageLink.textOffset)) {
45 url += '&textOffset=' + pageLink.textOffset; 45 url += '&textOffset=' + pageLink.textOffset;
46 } 46 }
47 - $http.get(url, null).then(function success(response) { 47 + $http.get(url, config).then(function success(response) {
48 deferred.resolve(response.data); 48 deferred.resolve(response.data);
49 }, function fail() { 49 }, function fail() {
50 deferred.reject(); 50 deferred.reject();
@@ -52,10 +52,10 @@ function CustomerService($http, $q, types) { @@ -52,10 +52,10 @@ function CustomerService($http, $q, types) {
52 return deferred.promise; 52 return deferred.promise;
53 } 53 }
54 54
55 - function getCustomer(customerId) { 55 + function getCustomer(customerId, config) {
56 var deferred = $q.defer(); 56 var deferred = $q.defer();
57 var url = '/api/customer/' + customerId; 57 var url = '/api/customer/' + customerId;
58 - $http.get(url, null).then(function success(response) { 58 + $http.get(url, config).then(function success(response) {
59 deferred.resolve(response.data); 59 deferred.resolve(response.data);
60 }, function fail(response) { 60 }, function fail(response) {
61 deferred.reject(response.data); 61 deferred.reject(response.data);
@@ -43,7 +43,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { @@ -43,7 +43,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) {
43 43
44 return service; 44 return service;
45 45
46 - function getTenantDashboardsByTenantId(tenantId, pageLink) { 46 + function getTenantDashboardsByTenantId(tenantId, pageLink, config) {
47 var deferred = $q.defer(); 47 var deferred = $q.defer();
48 var url = '/api/tenant/' + tenantId + '/dashboards?limit=' + pageLink.limit; 48 var url = '/api/tenant/' + tenantId + '/dashboards?limit=' + pageLink.limit;
49 if (angular.isDefined(pageLink.textSearch)) { 49 if (angular.isDefined(pageLink.textSearch)) {
@@ -55,7 +55,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { @@ -55,7 +55,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) {
55 if (angular.isDefined(pageLink.textOffset)) { 55 if (angular.isDefined(pageLink.textOffset)) {
56 url += '&textOffset=' + pageLink.textOffset; 56 url += '&textOffset=' + pageLink.textOffset;
57 } 57 }
58 - $http.get(url, null).then(function success(response) { 58 + $http.get(url, config).then(function success(response) {
59 deferred.resolve(response.data); 59 deferred.resolve(response.data);
60 }, function fail() { 60 }, function fail() {
61 deferred.reject(); 61 deferred.reject();
@@ -63,7 +63,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { @@ -63,7 +63,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) {
63 return deferred.promise; 63 return deferred.promise;
64 } 64 }
65 65
66 - function getTenantDashboards(pageLink, applyCustomersInfo) { 66 + function getTenantDashboards(pageLink, applyCustomersInfo, config) {
67 var deferred = $q.defer(); 67 var deferred = $q.defer();
68 var url = '/api/tenant/dashboards?limit=' + pageLink.limit; 68 var url = '/api/tenant/dashboards?limit=' + pageLink.limit;
69 if (angular.isDefined(pageLink.textSearch)) { 69 if (angular.isDefined(pageLink.textSearch)) {
@@ -75,7 +75,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { @@ -75,7 +75,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) {
75 if (angular.isDefined(pageLink.textOffset)) { 75 if (angular.isDefined(pageLink.textOffset)) {
76 url += '&textOffset=' + pageLink.textOffset; 76 url += '&textOffset=' + pageLink.textOffset;
77 } 77 }
78 - $http.get(url, null).then(function success(response) { 78 + $http.get(url, config).then(function success(response) {
79 if (applyCustomersInfo) { 79 if (applyCustomersInfo) {
80 customerService.applyAssignedCustomersInfo(response.data.data).then( 80 customerService.applyAssignedCustomersInfo(response.data.data).then(
81 function success(data) { 81 function success(data) {
@@ -95,7 +95,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { @@ -95,7 +95,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) {
95 return deferred.promise; 95 return deferred.promise;
96 } 96 }
97 97
98 - function getCustomerDashboards(customerId, pageLink, applyCustomersInfo) { 98 + function getCustomerDashboards(customerId, pageLink, applyCustomersInfo, config) {
99 var deferred = $q.defer(); 99 var deferred = $q.defer();
100 var url = '/api/customer/' + customerId + '/dashboards?limit=' + pageLink.limit; 100 var url = '/api/customer/' + customerId + '/dashboards?limit=' + pageLink.limit;
101 if (angular.isDefined(pageLink.textSearch)) { 101 if (angular.isDefined(pageLink.textSearch)) {
@@ -107,7 +107,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { @@ -107,7 +107,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) {
107 if (angular.isDefined(pageLink.textOffset)) { 107 if (angular.isDefined(pageLink.textOffset)) {
108 url += '&textOffset=' + pageLink.textOffset; 108 url += '&textOffset=' + pageLink.textOffset;
109 } 109 }
110 - $http.get(url, null).then(function success(response) { 110 + $http.get(url, config).then(function success(response) {
111 if (applyCustomersInfo) { 111 if (applyCustomersInfo) {
112 customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( 112 customerService.applyAssignedCustomerInfo(response.data.data, customerId).then(
113 function success(data) { 113 function success(data) {
@@ -158,10 +158,10 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { @@ -158,10 +158,10 @@ function DashboardService($rootScope, $http, $q, $location, customerService) {
158 return deferred.promise; 158 return deferred.promise;
159 } 159 }
160 160
161 - function getDashboardInfo(dashboardId) { 161 + function getDashboardInfo(dashboardId, config) {
162 var deferred = $q.defer(); 162 var deferred = $q.defer();
163 var url = '/api/dashboard/info/' + dashboardId; 163 var url = '/api/dashboard/info/' + dashboardId;
164 - $http.get(url, null).then(function success(response) { 164 + $http.get(url, config).then(function success(response) {
165 deferred.resolve(response.data); 165 deferred.resolve(response.data);
166 }, function fail() { 166 }, function fail() {
167 deferred.reject(); 167 deferred.reject();
@@ -293,10 +293,10 @@ function DeviceService($http, $q, attributeService, customerService, types) { @@ -293,10 +293,10 @@ function DeviceService($http, $q, attributeService, customerService, types) {
293 return deferred.promise; 293 return deferred.promise;
294 } 294 }
295 295
296 - function getDeviceTypes() { 296 + function getDeviceTypes(config) {
297 var deferred = $q.defer(); 297 var deferred = $q.defer();
298 var url = '/api/device/types'; 298 var url = '/api/device/types';
299 - $http.get(url).then(function success(response) { 299 + $http.get(url, config).then(function success(response) {
300 deferred.resolve(response.data); 300 deferred.resolve(response.data);
301 }, function fail() { 301 }, function fail() {
302 deferred.reject(); 302 deferred.reject();
@@ -175,10 +175,10 @@ function EntityRelationService($http, $q) { @@ -175,10 +175,10 @@ function EntityRelationService($http, $q) {
175 return deferred.promise; 175 return deferred.promise;
176 } 176 }
177 177
178 - function findInfoByQuery(query) { 178 + function findInfoByQuery(query, config) {
179 var deferred = $q.defer(); 179 var deferred = $q.defer();
180 var url = '/api/relations/info'; 180 var url = '/api/relations/info';
181 - $http.post(url, query).then(function success(response) { 181 + $http.post(url, query, config).then(function success(response) {
182 deferred.resolve(response.data); 182 deferred.resolve(response.data);
183 }, function fail() { 183 }, function fail() {
184 deferred.reject(); 184 deferred.reject();
@@ -56,22 +56,22 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -56,22 +56,22 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
56 promise = assetService.getAsset(entityId, true, config); 56 promise = assetService.getAsset(entityId, true, config);
57 break; 57 break;
58 case types.entityType.tenant: 58 case types.entityType.tenant:
59 - promise = tenantService.getTenant(entityId); 59 + promise = tenantService.getTenant(entityId, config);
60 break; 60 break;
61 case types.entityType.customer: 61 case types.entityType.customer:
62 - promise = customerService.getCustomer(entityId); 62 + promise = customerService.getCustomer(entityId, config);
63 break; 63 break;
64 case types.entityType.rule: 64 case types.entityType.rule:
65 - promise = ruleService.getRule(entityId); 65 + promise = ruleService.getRule(entityId, config);
66 break; 66 break;
67 case types.entityType.plugin: 67 case types.entityType.plugin:
68 - promise = pluginService.getPlugin(entityId); 68 + promise = pluginService.getPlugin(entityId, config);
69 break; 69 break;
70 case types.entityType.dashboard: 70 case types.entityType.dashboard:
71 - promise = dashboardService.getDashboardInfo(entityId); 71 + promise = dashboardService.getDashboardInfo(entityId, config);
72 break; 72 break;
73 case types.entityType.user: 73 case types.entityType.user:
74 - promise = userService.getUser(entityId); 74 + promise = userService.getUser(entityId, true, config);
75 break; 75 break;
76 case types.entityType.alarm: 76 case types.entityType.alarm:
77 $log.error('Get Alarm Entity is not implemented!'); 77 $log.error('Get Alarm Entity is not implemented!');
@@ -136,22 +136,28 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -136,22 +136,28 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
136 promise = assetService.getAssets(entityIds, config); 136 promise = assetService.getAssets(entityIds, config);
137 break; 137 break;
138 case types.entityType.tenant: 138 case types.entityType.tenant:
139 - promise = getEntitiesByIdsPromise(tenantService.getTenant, entityIds); 139 + promise = getEntitiesByIdsPromise(
  140 + (id) => tenantService.getTenant(id, config), entityIds);
140 break; 141 break;
141 case types.entityType.customer: 142 case types.entityType.customer:
142 - promise = getEntitiesByIdsPromise(customerService.getCustomer, entityIds); 143 + promise = getEntitiesByIdsPromise(
  144 + (id) => customerService.getCustomer(id, config), entityIds);
143 break; 145 break;
144 case types.entityType.rule: 146 case types.entityType.rule:
145 - promise = getEntitiesByIdsPromise(ruleService.getRule, entityIds); 147 + promise = getEntitiesByIdsPromise(
  148 + (id) => ruleService.getRule(id, config), entityIds);
146 break; 149 break;
147 case types.entityType.plugin: 150 case types.entityType.plugin:
148 - promise = getEntitiesByIdsPromise(pluginService.getPlugin, entityIds); 151 + promise = getEntitiesByIdsPromise(
  152 + (id) => pluginService.getPlugin(id, config), entityIds);
149 break; 153 break;
150 case types.entityType.dashboard: 154 case types.entityType.dashboard:
151 - promise = getEntitiesByIdsPromise(dashboardService.getDashboardInfo, entityIds); 155 + promise = getEntitiesByIdsPromise(
  156 + (id) => dashboardService.getDashboardInfo(id, config), entityIds);
152 break; 157 break;
153 case types.entityType.user: 158 case types.entityType.user:
154 - promise = getEntitiesByIdsPromise(userService.getUser, entityIds); 159 + promise = getEntitiesByIdsPromise(
  160 + (id) => userService.getUser(id, true, config), entityIds);
155 break; 161 break;
156 case types.entityType.alarm: 162 case types.entityType.alarm:
157 $log.error('Get Alarm Entity is not implemented!'); 163 $log.error('Get Alarm Entity is not implemented!');
@@ -178,11 +184,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -178,11 +184,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
178 return deferred.promise; 184 return deferred.promise;
179 } 185 }
180 186
181 - function getSingleTenantByPageLinkPromise(pageLink) { 187 + function getSingleTenantByPageLinkPromise(pageLink, config) {
182 var user = userService.getCurrentUser(); 188 var user = userService.getCurrentUser();
183 var tenantId = user.tenantId; 189 var tenantId = user.tenantId;
184 var deferred = $q.defer(); 190 var deferred = $q.defer();
185 - tenantService.getTenant(tenantId).then( 191 + tenantService.getTenant(tenantId, config).then(
186 function success(tenant) { 192 function success(tenant) {
187 var tenantName = tenant.name; 193 var tenantName = tenant.name;
188 var result = { 194 var result = {
@@ -202,11 +208,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -202,11 +208,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
202 return deferred.promise; 208 return deferred.promise;
203 } 209 }
204 210
205 - function getSingleCustomerByPageLinkPromise(pageLink) { 211 + function getSingleCustomerByPageLinkPromise(pageLink, config) {
206 var user = userService.getCurrentUser(); 212 var user = userService.getCurrentUser();
207 var customerId = user.customerId; 213 var customerId = user.customerId;
208 var deferred = $q.defer(); 214 var deferred = $q.defer();
209 - customerService.getCustomer(customerId).then( 215 + customerService.getCustomer(customerId, config).then(
210 function success(customer) { 216 function success(customer) {
211 var customerName = customer.name; 217 var customerName = customer.name;
212 var result = { 218 var result = {
@@ -247,29 +253,29 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -247,29 +253,29 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
247 break; 253 break;
248 case types.entityType.tenant: 254 case types.entityType.tenant:
249 if (user.authority === 'TENANT_ADMIN') { 255 if (user.authority === 'TENANT_ADMIN') {
250 - promise = getSingleTenantByPageLinkPromise(pageLink); 256 + promise = getSingleTenantByPageLinkPromise(pageLink, config);
251 } else { 257 } else {
252 - promise = tenantService.getTenants(pageLink); 258 + promise = tenantService.getTenants(pageLink, config);
253 } 259 }
254 break; 260 break;
255 case types.entityType.customer: 261 case types.entityType.customer:
256 if (user.authority === 'CUSTOMER_USER') { 262 if (user.authority === 'CUSTOMER_USER') {
257 - promise = getSingleCustomerByPageLinkPromise(pageLink); 263 + promise = getSingleCustomerByPageLinkPromise(pageLink, config);
258 } else { 264 } else {
259 - promise = customerService.getCustomers(pageLink); 265 + promise = customerService.getCustomers(pageLink, config);
260 } 266 }
261 break; 267 break;
262 case types.entityType.rule: 268 case types.entityType.rule:
263 - promise = ruleService.getAllRules(pageLink); 269 + promise = ruleService.getAllRules(pageLink, config);
264 break; 270 break;
265 case types.entityType.plugin: 271 case types.entityType.plugin:
266 - promise = pluginService.getAllPlugins(pageLink); 272 + promise = pluginService.getAllPlugins(pageLink, config);
267 break; 273 break;
268 case types.entityType.dashboard: 274 case types.entityType.dashboard:
269 if (user.authority === 'CUSTOMER_USER') { 275 if (user.authority === 'CUSTOMER_USER') {
270 - promise = dashboardService.getCustomerDashboards(customerId, pageLink, false); 276 + promise = dashboardService.getCustomerDashboards(customerId, pageLink, false, config);
271 } else { 277 } else {
272 - promise = dashboardService.getTenantDashboards(pageLink, false); 278 + promise = dashboardService.getTenantDashboards(pageLink, false, config);
273 } 279 }
274 break; 280 break;
275 case types.entityType.user: 281 case types.entityType.user:
@@ -426,7 +432,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -426,7 +432,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
426 var stateEntityId = getStateEntityId(filter, stateParams); 432 var stateEntityId = getStateEntityId(filter, stateParams);
427 switch (filter.type) { 433 switch (filter.type) {
428 case types.aliasFilterType.singleEntity.value: 434 case types.aliasFilterType.singleEntity.value:
429 - getEntity(filter.singleEntity.entityType, filter.singleEntity.id).then( 435 + getEntity(filter.singleEntity.entityType, filter.singleEntity.id, {ignoreLoading: true}).then(
430 function success(entity) { 436 function success(entity) {
431 result.entities = entitiesToEntitiesInfo([entity]); 437 result.entities = entitiesToEntitiesInfo([entity]);
432 deferred.resolve(result); 438 deferred.resolve(result);
@@ -437,7 +443,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -437,7 +443,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
437 ); 443 );
438 break; 444 break;
439 case types.aliasFilterType.entityList.value: 445 case types.aliasFilterType.entityList.value:
440 - getEntities(filter.entityType, filter.entityList).then( 446 + getEntities(filter.entityType, filter.entityList, {ignoreLoading: true}).then(
441 function success(entities) { 447 function success(entities) {
442 if (entities && entities.length || !failOnEmpty) { 448 if (entities && entities.length || !failOnEmpty) {
443 result.entities = entitiesToEntitiesInfo(entities); 449 result.entities = entitiesToEntitiesInfo(entities);
@@ -452,7 +458,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -452,7 +458,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
452 ); 458 );
453 break; 459 break;
454 case types.aliasFilterType.entityName.value: 460 case types.aliasFilterType.entityName.value:
455 - getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then( 461 + getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems, {ignoreLoading: true}).then(
456 function success(entities) { 462 function success(entities) {
457 if (entities && entities.length || !failOnEmpty) { 463 if (entities && entities.length || !failOnEmpty) {
458 result.entities = entitiesToEntitiesInfo(entities); 464 result.entities = entitiesToEntitiesInfo(entities);
@@ -469,7 +475,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -469,7 +475,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
469 case types.aliasFilterType.stateEntity.value: 475 case types.aliasFilterType.stateEntity.value:
470 result.stateEntity = true; 476 result.stateEntity = true;
471 if (stateEntityId) { 477 if (stateEntityId) {
472 - getEntity(stateEntityId.entityType, stateEntityId.id).then( 478 + getEntity(stateEntityId.entityType, stateEntityId.id, {ignoreLoading: true}).then(
473 function success(entity) { 479 function success(entity) {
474 result.entities = entitiesToEntitiesInfo([entity]); 480 result.entities = entitiesToEntitiesInfo([entity]);
475 deferred.resolve(result); 481 deferred.resolve(result);
@@ -483,7 +489,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -483,7 +489,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
483 } 489 }
484 break; 490 break;
485 case types.aliasFilterType.assetType.value: 491 case types.aliasFilterType.assetType.value:
486 - getEntitiesByNameFilter(types.entityType.asset, filter.assetNameFilter, maxItems, null, filter.assetType).then( 492 + getEntitiesByNameFilter(types.entityType.asset, filter.assetNameFilter, maxItems, {ignoreLoading: true}, filter.assetType).then(
487 function success(entities) { 493 function success(entities) {
488 if (entities && entities.length || !failOnEmpty) { 494 if (entities && entities.length || !failOnEmpty) {
489 result.entities = entitiesToEntitiesInfo(entities); 495 result.entities = entitiesToEntitiesInfo(entities);
@@ -498,7 +504,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -498,7 +504,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
498 ); 504 );
499 break; 505 break;
500 case types.aliasFilterType.deviceType.value: 506 case types.aliasFilterType.deviceType.value:
501 - getEntitiesByNameFilter(types.entityType.device, filter.deviceNameFilter, maxItems, null, filter.deviceType).then( 507 + getEntitiesByNameFilter(types.entityType.device, filter.deviceNameFilter, maxItems, {ignoreLoading: true}, filter.deviceType).then(
502 function success(entities) { 508 function success(entities) {
503 if (entities && entities.length || !failOnEmpty) { 509 if (entities && entities.length || !failOnEmpty) {
504 result.entities = entitiesToEntitiesInfo(entities); 510 result.entities = entitiesToEntitiesInfo(entities);
@@ -533,7 +539,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -533,7 +539,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
533 filters: filter.filters 539 filters: filter.filters
534 }; 540 };
535 searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1; 541 searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1;
536 - entityRelationService.findInfoByQuery(searchQuery).then( 542 + entityRelationService.findInfoByQuery(searchQuery, {ignoreLoading: true}).then(
537 function success(allRelations) { 543 function success(allRelations) {
538 if (allRelations && allRelations.length || !failOnEmpty) { 544 if (allRelations && allRelations.length || !failOnEmpty) {
539 if (angular.isDefined(maxItems) && maxItems > 0 && allRelations) { 545 if (angular.isDefined(maxItems) && maxItems > 0 && allRelations) {
@@ -577,10 +583,10 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -577,10 +583,10 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
577 var findByQueryPromise; 583 var findByQueryPromise;
578 if (filter.type == types.aliasFilterType.assetSearchQuery.value) { 584 if (filter.type == types.aliasFilterType.assetSearchQuery.value) {
579 searchQuery.assetTypes = filter.assetTypes; 585 searchQuery.assetTypes = filter.assetTypes;
580 - findByQueryPromise = assetService.findByQuery(searchQuery, false); 586 + findByQueryPromise = assetService.findByQuery(searchQuery, false, {ignoreLoading: true});
581 } else if (filter.type == types.aliasFilterType.deviceSearchQuery.value) { 587 } else if (filter.type == types.aliasFilterType.deviceSearchQuery.value) {
582 searchQuery.deviceTypes = filter.deviceTypes; 588 searchQuery.deviceTypes = filter.deviceTypes;
583 - findByQueryPromise = deviceService.findByQuery(searchQuery, false); 589 + findByQueryPromise = deviceService.findByQuery(searchQuery, false, {ignoreLoading: true});
584 } 590 }
585 findByQueryPromise.then( 591 findByQueryPromise.then(
586 function success(entities) { 592 function success(entities) {
@@ -762,7 +768,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -762,7 +768,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
762 return deferred.promise; 768 return deferred.promise;
763 } 769 }
764 770
765 - function getEntityKeys(entityType, entityId, query, type) { 771 + function getEntityKeys(entityType, entityId, query, type, config) {
766 var deferred = $q.defer(); 772 var deferred = $q.defer();
767 var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; 773 var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/';
768 if (type === types.dataKeyType.timeseries) { 774 if (type === types.dataKeyType.timeseries) {
@@ -770,7 +776,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -770,7 +776,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
770 } else if (type === types.dataKeyType.attribute) { 776 } else if (type === types.dataKeyType.attribute) {
771 url += 'attributes'; 777 url += 'attributes';
772 } 778 }
773 - $http.get(url, null).then(function success(response) { 779 + $http.get(url, config).then(function success(response) {
774 var result = []; 780 var result = [];
775 if (response.data) { 781 if (response.data) {
776 if (query) { 782 if (query) {
@@ -50,11 +50,11 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic @@ -50,11 +50,11 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic
50 tenantPlugins = undefined; 50 tenantPlugins = undefined;
51 } 51 }
52 52
53 - function loadPluginsCache() { 53 + function loadPluginsCache(config) {
54 var deferred = $q.defer(); 54 var deferred = $q.defer();
55 if (!allPlugins) { 55 if (!allPlugins) {
56 var url = '/api/plugins'; 56 var url = '/api/plugins';
57 - $http.get(url, null).then(function success(response) { 57 + $http.get(url, config).then(function success(response) {
58 componentDescriptorService.getComponentDescriptorsByType(types.componentType.plugin).then( 58 componentDescriptorService.getComponentDescriptorsByType(types.componentType.plugin).then(
59 function success(pluginComponents) { 59 function success(pluginComponents) {
60 allPlugins = response.data; 60 allPlugins = response.data;
@@ -93,9 +93,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic @@ -93,9 +93,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic
93 return deferred.promise; 93 return deferred.promise;
94 } 94 }
95 95
96 - function getSystemPlugins(pageLink) { 96 + function getSystemPlugins(pageLink, config) {
97 var deferred = $q.defer(); 97 var deferred = $q.defer();
98 - loadPluginsCache().then( 98 + loadPluginsCache(config).then(
99 function success() { 99 function success() {
100 utils.filterSearchTextEntities(systemPlugins, 'name', pageLink, deferred); 100 utils.filterSearchTextEntities(systemPlugins, 'name', pageLink, deferred);
101 }, 101 },
@@ -106,9 +106,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic @@ -106,9 +106,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic
106 return deferred.promise; 106 return deferred.promise;
107 } 107 }
108 108
109 - function getTenantPlugins(pageLink) { 109 + function getTenantPlugins(pageLink, config) {
110 var deferred = $q.defer(); 110 var deferred = $q.defer();
111 - loadPluginsCache().then( 111 + loadPluginsCache(config).then(
112 function success() { 112 function success() {
113 utils.filterSearchTextEntities(tenantPlugins, 'name', pageLink, deferred); 113 utils.filterSearchTextEntities(tenantPlugins, 'name', pageLink, deferred);
114 }, 114 },
@@ -119,9 +119,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic @@ -119,9 +119,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic
119 return deferred.promise; 119 return deferred.promise;
120 } 120 }
121 121
122 - function getAllActionPlugins(pageLink) { 122 + function getAllActionPlugins(pageLink, config) {
123 var deferred = $q.defer(); 123 var deferred = $q.defer();
124 - loadPluginsCache().then( 124 + loadPluginsCache(config).then(
125 function success() { 125 function success() {
126 utils.filterSearchTextEntities(allActionPlugins, 'name', pageLink, deferred); 126 utils.filterSearchTextEntities(allActionPlugins, 'name', pageLink, deferred);
127 }, 127 },
@@ -132,9 +132,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic @@ -132,9 +132,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic
132 return deferred.promise; 132 return deferred.promise;
133 } 133 }
134 134
135 - function getAllPlugins(pageLink) { 135 + function getAllPlugins(pageLink, config) {
136 var deferred = $q.defer(); 136 var deferred = $q.defer();
137 - loadPluginsCache().then( 137 + loadPluginsCache(config).then(
138 function success() { 138 function success() {
139 utils.filterSearchTextEntities(allPlugins, 'name', pageLink, deferred); 139 utils.filterSearchTextEntities(allPlugins, 'name', pageLink, deferred);
140 }, 140 },
@@ -156,10 +156,10 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic @@ -156,10 +156,10 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic
156 return deferred.promise; 156 return deferred.promise;
157 } 157 }
158 158
159 - function getPlugin(pluginId) { 159 + function getPlugin(pluginId, config) {
160 var deferred = $q.defer(); 160 var deferred = $q.defer();
161 var url = '/api/plugin/' + pluginId; 161 var url = '/api/plugin/' + pluginId;
162 - $http.get(url, null).then(function success(response) { 162 + $http.get(url, config).then(function success(response) {
163 deferred.resolve(response.data); 163 deferred.resolve(response.data);
164 }, function fail(response) { 164 }, function fail(response) {
165 deferred.reject(response.data); 165 deferred.reject(response.data);
@@ -47,11 +47,11 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) { @@ -47,11 +47,11 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) {
47 tenantRules = undefined; 47 tenantRules = undefined;
48 } 48 }
49 49
50 - function loadRulesCache() { 50 + function loadRulesCache(config) {
51 var deferred = $q.defer(); 51 var deferred = $q.defer();
52 if (!allRules) { 52 if (!allRules) {
53 var url = '/api/rules'; 53 var url = '/api/rules';
54 - $http.get(url, null).then(function success(response) { 54 + $http.get(url, config).then(function success(response) {
55 allRules = response.data; 55 allRules = response.data;
56 systemRules = []; 56 systemRules = [];
57 tenantRules = []; 57 tenantRules = [];
@@ -100,9 +100,9 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) { @@ -100,9 +100,9 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) {
100 return deferred.promise; 100 return deferred.promise;
101 } 101 }
102 102
103 - function getAllRules(pageLink) { 103 + function getAllRules(pageLink, config) {
104 var deferred = $q.defer(); 104 var deferred = $q.defer();
105 - loadRulesCache().then( 105 + loadRulesCache(config).then(
106 function success() { 106 function success() {
107 utils.filterSearchTextEntities(allRules, 'name', pageLink, deferred); 107 utils.filterSearchTextEntities(allRules, 'name', pageLink, deferred);
108 }, 108 },
@@ -124,10 +124,10 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) { @@ -124,10 +124,10 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) {
124 return deferred.promise; 124 return deferred.promise;
125 } 125 }
126 126
127 - function getRule(ruleId) { 127 + function getRule(ruleId, config) {
128 var deferred = $q.defer(); 128 var deferred = $q.defer();
129 var url = '/api/rule/' + ruleId; 129 var url = '/api/rule/' + ruleId;
130 - $http.get(url, null).then(function success(response) { 130 + $http.get(url, config).then(function success(response) {
131 deferred.resolve(response.data); 131 deferred.resolve(response.data);
132 }, function fail(response) { 132 }, function fail(response) {
133 deferred.reject(response.data); 133 deferred.reject(response.data);
@@ -23,6 +23,8 @@ export default angular.module('thingsboard.api.telemetryWebsocket', [thingsboard @@ -23,6 +23,8 @@ export default angular.module('thingsboard.api.telemetryWebsocket', [thingsboard
23 const RECONNECT_INTERVAL = 2000; 23 const RECONNECT_INTERVAL = 2000;
24 const WS_IDLE_TIMEOUT = 90000; 24 const WS_IDLE_TIMEOUT = 90000;
25 25
  26 +const MAX_PUBLISH_COMMANDS = 10;
  27 +
26 /*@ngInject*/ 28 /*@ngInject*/
27 function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, types, userService) { 29 function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, types, userService) {
28 30
@@ -75,19 +77,40 @@ function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, ty @@ -75,19 +77,40 @@ function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, ty
75 return service; 77 return service;
76 78
77 function publishCommands () { 79 function publishCommands () {
78 - if (isOpened && (cmdsWrapper.tsSubCmds.length > 0 ||  
79 - cmdsWrapper.historyCmds.length > 0 ||  
80 - cmdsWrapper.attrSubCmds.length > 0)) {  
81 - dataStream.send(angular.copy(cmdsWrapper)).then(function () { 80 + while(isOpened && hasCommands()) {
  81 + dataStream.send(preparePublishCommands()).then(function () {
82 checkToClose(); 82 checkToClose();
83 }); 83 });
84 - cmdsWrapper.tsSubCmds = [];  
85 - cmdsWrapper.historyCmds = [];  
86 - cmdsWrapper.attrSubCmds = [];  
87 } 84 }
88 tryOpenSocket(); 85 tryOpenSocket();
89 } 86 }
90 87
  88 + function hasCommands() {
  89 + return cmdsWrapper.tsSubCmds.length > 0 ||
  90 + cmdsWrapper.historyCmds.length > 0 ||
  91 + cmdsWrapper.attrSubCmds.length > 0;
  92 + }
  93 +
  94 + function preparePublishCommands() {
  95 + var preparedWrapper = {};
  96 + var leftCount = MAX_PUBLISH_COMMANDS;
  97 + preparedWrapper.tsSubCmds = popCmds(cmdsWrapper.tsSubCmds, leftCount);
  98 + leftCount -= preparedWrapper.tsSubCmds.length;
  99 + preparedWrapper.historyCmds = popCmds(cmdsWrapper.historyCmds, leftCount);
  100 + leftCount -= preparedWrapper.historyCmds.length;
  101 + preparedWrapper.attrSubCmds = popCmds(cmdsWrapper.attrSubCmds, leftCount);
  102 + return preparedWrapper;
  103 + }
  104 +
  105 + function popCmds(cmds, leftCount) {
  106 + var toPublish = Math.min(cmds.length, leftCount);
  107 + if (toPublish > 0) {
  108 + return cmds.splice(0, toPublish);
  109 + } else {
  110 + return [];
  111 + }
  112 + }
  113 +
91 function onError (/*message*/) { 114 function onError (/*message*/) {
92 isOpening = false; 115 isOpening = false;
93 } 116 }
@@ -29,7 +29,7 @@ function TenantService($http, $q) { @@ -29,7 +29,7 @@ function TenantService($http, $q) {
29 29
30 return service; 30 return service;
31 31
32 - function getTenants (pageLink) { 32 + function getTenants (pageLink, config) {
33 var deferred = $q.defer(); 33 var deferred = $q.defer();
34 var url = '/api/tenants?limit=' + pageLink.limit; 34 var url = '/api/tenants?limit=' + pageLink.limit;
35 if (angular.isDefined(pageLink.textSearch)) { 35 if (angular.isDefined(pageLink.textSearch)) {
@@ -41,7 +41,7 @@ function TenantService($http, $q) { @@ -41,7 +41,7 @@ function TenantService($http, $q) {
41 if (angular.isDefined(pageLink.textOffset)) { 41 if (angular.isDefined(pageLink.textOffset)) {
42 url += '&textOffset=' + pageLink.textOffset; 42 url += '&textOffset=' + pageLink.textOffset;
43 } 43 }
44 - $http.get(url, null).then(function success(response) { 44 + $http.get(url, config).then(function success(response) {
45 deferred.resolve(response.data); 45 deferred.resolve(response.data);
46 }, function fail() { 46 }, function fail() {
47 deferred.reject(); 47 deferred.reject();
@@ -49,10 +49,10 @@ function TenantService($http, $q) { @@ -49,10 +49,10 @@ function TenantService($http, $q) {
49 return deferred.promise; 49 return deferred.promise;
50 } 50 }
51 51
52 - function getTenant (tenantId) { 52 + function getTenant (tenantId, config) {
53 var deferred = $q.defer(); 53 var deferred = $q.defer();
54 var url = '/api/tenant/' + tenantId; 54 var url = '/api/tenant/' + tenantId;
55 - $http.get(url, null).then(function success(response) { 55 + $http.get(url, config).then(function success(response) {
56 deferred.resolve(response.data); 56 deferred.resolve(response.data);
57 }, function fail(response) { 57 }, function fail(response) {
58 deferred.reject(response.data); 58 deferred.reject(response.data);
@@ -421,10 +421,14 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi @@ -421,10 +421,14 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
421 return deferred.promise; 421 return deferred.promise;
422 } 422 }
423 423
424 - function getUser(userId, ignoreErrors) { 424 + function getUser(userId, ignoreErrors, config) {
425 var deferred = $q.defer(); 425 var deferred = $q.defer();
426 var url = '/api/user/' + userId; 426 var url = '/api/user/' + userId;
427 - $http.get(url, { ignoreErrors: ignoreErrors }).then(function success(response) { 427 + if (!config) {
  428 + config = {};
  429 + }
  430 + config = Object.assign(config, { ignoreErrors: ignoreErrors });
  431 + $http.get(url, config).then(function success(response) {
428 deferred.resolve(response.data); 432 deferred.resolve(response.data);
429 }, function fail() { 433 }, function fail() {
430 deferred.reject(); 434 deferred.reject();
@@ -298,11 +298,11 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr @@ -298,11 +298,11 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
298 tenantWidgetsBundles = undefined; 298 tenantWidgetsBundles = undefined;
299 } 299 }
300 300
301 - function loadWidgetsBundleCache() { 301 + function loadWidgetsBundleCache(config) {
302 var deferred = $q.defer(); 302 var deferred = $q.defer();
303 if (!allWidgetsBundles) { 303 if (!allWidgetsBundles) {
304 var url = '/api/widgetsBundles'; 304 var url = '/api/widgetsBundles';
305 - $http.get(url, null).then(function success(response) { 305 + $http.get(url, config).then(function success(response) {
306 allWidgetsBundles = response.data; 306 allWidgetsBundles = response.data;
307 systemWidgetsBundles = []; 307 systemWidgetsBundles = [];
308 tenantWidgetsBundles = []; 308 tenantWidgetsBundles = [];
@@ -326,9 +326,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr @@ -326,9 +326,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
326 } 326 }
327 327
328 328
329 - function getSystemWidgetsBundles() { 329 + function getSystemWidgetsBundles(config) {
330 var deferred = $q.defer(); 330 var deferred = $q.defer();
331 - loadWidgetsBundleCache().then( 331 + loadWidgetsBundleCache(config).then(
332 function success() { 332 function success() {
333 deferred.resolve(systemWidgetsBundles); 333 deferred.resolve(systemWidgetsBundles);
334 }, 334 },
@@ -339,9 +339,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr @@ -339,9 +339,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
339 return deferred.promise; 339 return deferred.promise;
340 } 340 }
341 341
342 - function getTenantWidgetsBundles() { 342 + function getTenantWidgetsBundles(config) {
343 var deferred = $q.defer(); 343 var deferred = $q.defer();
344 - loadWidgetsBundleCache().then( 344 + loadWidgetsBundleCache(config).then(
345 function success() { 345 function success() {
346 deferred.resolve(tenantWidgetsBundles); 346 deferred.resolve(tenantWidgetsBundles);
347 }, 347 },
@@ -352,9 +352,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr @@ -352,9 +352,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
352 return deferred.promise; 352 return deferred.promise;
353 } 353 }
354 354
355 - function getAllWidgetsBundles() { 355 + function getAllWidgetsBundles(config) {
356 var deferred = $q.defer(); 356 var deferred = $q.defer();
357 - loadWidgetsBundleCache().then( 357 + loadWidgetsBundleCache(config).then(
358 function success() { 358 function success() {
359 deferred.resolve(allWidgetsBundles); 359 deferred.resolve(allWidgetsBundles);
360 }, 360 },
@@ -27,8 +27,8 @@ @@ -27,8 +27,8 @@
27 </md-button> 27 </md-button>
28 </div> 28 </div>
29 </md-toolbar> 29 </md-toolbar>
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
31 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 30 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  31 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
32 <md-dialog-content> 32 <md-dialog-content>
33 <div class="md-dialog-content"> 33 <div class="md-dialog-content">
34 <tb-asset asset="vm.item" is-edit="true" the-form="theForm"></tb-asset> 34 <tb-asset asset="vm.item" is-edit="true" the-form="theForm"></tb-asset>
@@ -36,10 +36,10 @@ @@ -36,10 +36,10 @@
36 </md-dialog-content> 36 </md-dialog-content>
37 <md-dialog-actions layout="row"> 37 <md-dialog-actions layout="row">
38 <span flex></span> 38 <span flex></span>
39 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 39 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
40 {{ 'action.add' | translate }} 40 {{ 'action.add' | translate }}
41 </md-button> 41 </md-button>
42 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 42 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
43 </md-dialog-actions> 43 </md-dialog-actions>
44 </form> 44 </form>
45 </md-dialog> 45 </md-dialog>
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <fieldset> 33 <fieldset>
@@ -65,11 +65,11 @@ @@ -65,11 +65,11 @@
65 </md-dialog-content> 65 </md-dialog-content>
66 <md-dialog-actions layout="row"> 66 <md-dialog-actions layout="row">
67 <span flex></span> 67 <span flex></span>
68 - <md-button ng-disabled="loading || vm.assets.selectedCount == 0" type="submit" 68 + <md-button ng-disabled="$root.loading || vm.assets.selectedCount == 0" type="submit"
69 class="md-raised md-primary"> 69 class="md-raised md-primary">
70 {{ 'action.assign' | translate }} 70 {{ 'action.assign' | translate }}
71 </md-button> 71 </md-button>
72 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 72 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
73 translate }} 73 translate }}
74 </md-button> 74 </md-button>
75 </md-dialog-actions> 75 </md-dialog-actions>
@@ -48,7 +48,7 @@ @@ -48,7 +48,7 @@
48 ng-show="!isEdit && isPublic && (assetScope === 'customer' || assetScope === 'tenant')"> 48 ng-show="!isEdit && isPublic && (assetScope === 'customer' || assetScope === 'tenant')">
49 {{ 'asset.asset-public' | translate }} 49 {{ 'asset.asset-public' | translate }}
50 </div> 50 </div>
51 - <fieldset ng-disabled="loading || !isEdit"> 51 + <fieldset ng-disabled="$root.loading || !isEdit">
52 <md-input-container class="md-block"> 52 <md-input-container class="md-block">
53 <label translate>asset.name</label> 53 <label translate>asset.name</label>
54 <input required name="name" ng-model="asset.name"> 54 <input required name="name" ng-model="asset.name">
@@ -57,7 +57,7 @@ @@ -57,7 +57,7 @@
57 </div> 57 </div>
58 </md-input-container> 58 </md-input-container>
59 <tb-entity-subtype-autocomplete 59 <tb-entity-subtype-autocomplete
60 - ng-disabled="loading || !isEdit" 60 + ng-disabled="$root.loading || !isEdit"
61 tb-required="true" 61 tb-required="true"
62 the-form="theForm" 62 the-form="theForm"
63 ng-model="asset.type" 63 ng-model="asset.type"
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <fieldset> 33 <fieldset>
@@ -65,10 +65,10 @@ @@ -65,10 +65,10 @@
65 </md-dialog-content> 65 </md-dialog-content>
66 <md-dialog-actions layout="row"> 66 <md-dialog-actions layout="row">
67 <span flex></span> 67 <span flex></span>
68 - <md-button ng-disabled="loading || vm.customers.selection==null" type="submit" class="md-raised md-primary"> 68 + <md-button ng-disabled="$root.loading || vm.customers.selection==null" type="submit" class="md-raised md-primary">
69 {{ 'action.assign' | translate }} 69 {{ 'action.assign' | translate }}
70 </md-button> 70 </md-button>
71 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 71 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
72 translate }} 72 translate }}
73 </md-button> 73 </md-button>
74 </md-dialog-actions> 74 </md-dialog-actions>
@@ -134,6 +134,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t @@ -134,6 +134,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t
134 defaultAlarmDataKeys.push(dataKey); 134 defaultAlarmDataKeys.push(dataKey);
135 } 135 }
136 136
  137 + var imageAspectMap = {};
  138 +
137 var service = { 139 var service = {
138 getDefaultDatasource: getDefaultDatasource, 140 getDefaultDatasource: getDefaultDatasource,
139 generateObjectFromJsonSchema: generateObjectFromJsonSchema, 141 generateObjectFromJsonSchema: generateObjectFromJsonSchema,
@@ -159,7 +161,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t @@ -159,7 +161,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t
159 insertVariable: insertVariable, 161 insertVariable: insertVariable,
160 customTranslation: customTranslation, 162 customTranslation: customTranslation,
161 objToBase64: objToBase64, 163 objToBase64: objToBase64,
162 - base64toObj: base64toObj 164 + base64toObj: base64toObj,
  165 + loadImageAspect: loadImageAspect
163 } 166 }
164 167
165 return service; 168 return service;
@@ -543,4 +546,34 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t @@ -543,4 +546,34 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t
543 return obj; 546 return obj;
544 } 547 }
545 548
  549 + function loadImageAspect(imageUrl) {
  550 + var deferred = $q.defer();
  551 + if (imageUrl && imageUrl.length) {
  552 + var urlHashCode = hashCode(imageUrl);
  553 + var aspect = imageAspectMap[urlHashCode];
  554 + if (angular.isUndefined(aspect)) {
  555 + var testImage = document.createElement('img'); // eslint-disable-line
  556 + testImage.style.visibility = 'hidden';
  557 + testImage.onload = function() {
  558 + aspect = testImage.width / testImage.height;
  559 + document.body.removeChild(testImage); //eslint-disable-line
  560 + imageAspectMap[urlHashCode] = aspect;
  561 + deferred.resolve(aspect);
  562 + };
  563 + testImage.onerror = function() {
  564 + aspect = 0;
  565 + imageAspectMap[urlHashCode] = aspect;
  566 + deferred.resolve(aspect);
  567 + };
  568 + document.body.appendChild(testImage); //eslint-disable-line
  569 + testImage.src = imageUrl;
  570 + } else {
  571 + deferred.resolve(aspect);
  572 + }
  573 + } else {
  574 + deferred.resolve(0);
  575 + }
  576 + return deferred.promise;
  577 + }
  578 +
546 } 579 }
@@ -27,11 +27,11 @@ @@ -27,11 +27,11 @@
27 </md-button> 27 </md-button>
28 </div> 28 </div>
29 </md-toolbar> 29 </md-toolbar>
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
31 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 30 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  31 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
32 <md-dialog-content> 32 <md-dialog-content>
33 <div class="md-dialog-content tb-filter"> 33 <div class="md-dialog-content tb-filter">
34 - <fieldset ng-disabled="loading || vm.isReadOnly"> 34 + <fieldset ng-disabled="$root.loading || vm.isReadOnly">
35 <section flex layout="row"> 35 <section flex layout="row">
36 <md-input-container flex class="md-block"> 36 <md-input-container flex class="md-block">
37 <label translate>rule.component-name</label> 37 <label translate>rule.component-name</label>
@@ -42,7 +42,7 @@ @@ -42,7 +42,7 @@
42 </md-input-container> 42 </md-input-container>
43 <md-input-container flex class="md-block"> 43 <md-input-container flex class="md-block">
44 <label translate>rule.component-type</label> 44 <label translate>rule.component-type</label>
45 - <md-select required name="componentType" ng-model="vm.componentInfo.component.clazz" ng-disabled="loading || vm.isReadOnly"> 45 + <md-select required name="componentType" ng-model="vm.componentInfo.component.clazz" ng-disabled="$root.loading || vm.isReadOnly">
46 <md-option ng-repeat="componentDescriptor in vm.componentDescriptors" ng-value="componentDescriptor.clazz"> 46 <md-option ng-repeat="componentDescriptor in vm.componentDescriptors" ng-value="componentDescriptor.clazz">
47 {{componentDescriptor.name}} 47 {{componentDescriptor.name}}
48 </md-option> 48 </md-option>
@@ -57,7 +57,7 @@ @@ -57,7 +57,7 @@
57 <tb-json-form schema="vm.componentDescriptor.configurationDescriptor.schema" 57 <tb-json-form schema="vm.componentDescriptor.configurationDescriptor.schema"
58 form="vm.componentDescriptor.configurationDescriptor.form" 58 form="vm.componentDescriptor.configurationDescriptor.form"
59 model="vm.componentInfo.component.configuration" 59 model="vm.componentInfo.component.configuration"
60 - readonly="loading || vm.isReadOnly" 60 + readonly="$root.loading || vm.isReadOnly"
61 form-control="theForm"> 61 form-control="theForm">
62 </tb-json-form> 62 </tb-json-form>
63 </md-card-content> 63 </md-card-content>
@@ -67,11 +67,11 @@ @@ -67,11 +67,11 @@
67 </md-dialog-content> 67 </md-dialog-content>
68 <md-dialog-actions layout="row"> 68 <md-dialog-actions layout="row">
69 <span flex></span> 69 <span flex></span>
70 - <md-button ng-if="!vm.isReadOnly" ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" 70 + <md-button ng-if="!vm.isReadOnly" ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit"
71 class="md-raised md-primary"> 71 class="md-raised md-primary">
72 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} 72 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }}
73 </md-button> 73 </md-button>
74 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 74 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
75 translate }} 75 translate }}
76 </md-button> 76 </md-button>
77 </md-dialog-actions> 77 </md-dialog-actions>
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 {{ componentTypeName }} 24 {{ componentTypeName }}
25 </span> 25 </span>
26 <span ng-if="readOnly" style="min-width: 40px; min-height: 40px; margin: 0 6px;"></br></span> 26 <span ng-if="readOnly" style="min-width: 40px; min-height: 40px; margin: 0 6px;"></br></span>
27 - <md-button ng-disabled="loading" class="md-icon-button md-primary" 27 + <md-button ng-disabled="$root.loading" class="md-icon-button md-primary"
28 style="min-width: 40px;" 28 style="min-width: 40px;"
29 ng-click="openComponent($event)" 29 ng-click="openComponent($event)"
30 aria-label="{{ (readOnly ? 'action.view' : 'action.edit') | translate }}"> 30 aria-label="{{ (readOnly ? 'action.view' : 'action.edit') | translate }}">
@@ -43,7 +43,7 @@ @@ -43,7 +43,7 @@
43 edit 43 edit
44 </md-icon> 44 </md-icon>
45 </md-button> 45 </md-button>
46 - <md-button ng-if="!readOnly" ng-disabled="loading" class="md-icon-button md-primary" 46 + <md-button ng-if="!readOnly" ng-disabled="$root.loading" class="md-icon-button md-primary"
47 style="min-width: 40px;" 47 style="min-width: 40px;"
48 ng-click="onRemoveComponent({event: $event})" 48 ng-click="onRemoveComponent({event: $event})"
49 aria-label="{{ 'action.remove' | translate }}"> 49 aria-label="{{ 'action.remove' | translate }}">
@@ -48,19 +48,19 @@ function DashboardAutocomplete($compile, $templateCache, $q, dashboardService, u @@ -48,19 +48,19 @@ function DashboardAutocomplete($compile, $templateCache, $q, dashboardService, u
48 var promise; 48 var promise;
49 if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') { 49 if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') {
50 if (scope.customerId) { 50 if (scope.customerId) {
51 - promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false); 51 + promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false, {ignoreLoading: true});
52 } else { 52 } else {
53 promise = $q.when({data: []}); 53 promise = $q.when({data: []});
54 } 54 }
55 } else { 55 } else {
56 if (userService.getAuthority() === 'SYS_ADMIN') { 56 if (userService.getAuthority() === 'SYS_ADMIN') {
57 if (scope.tenantId) { 57 if (scope.tenantId) {
58 - promise = dashboardService.getTenantDashboardsByTenantId(scope.tenantId, pageLink); 58 + promise = dashboardService.getTenantDashboardsByTenantId(scope.tenantId, pageLink, {ignoreLoading: true});
59 } else { 59 } else {
60 promise = $q.when({data: []}); 60 promise = $q.when({data: []});
61 } 61 }
62 } else { 62 } else {
63 - promise = dashboardService.getTenantDashboards(pageLink, false); 63 + promise = dashboardService.getTenantDashboards(pageLink, false, {ignoreLoading: true});
64 } 64 }
65 } 65 }
66 66
@@ -48,12 +48,12 @@ function DashboardSelect($compile, $templateCache, $q, $mdMedia, $mdPanel, $docu @@ -48,12 +48,12 @@ function DashboardSelect($compile, $templateCache, $q, $mdMedia, $mdPanel, $docu
48 var promise; 48 var promise;
49 if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') { 49 if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') {
50 if (scope.customerId && scope.customerId != types.id.nullUid) { 50 if (scope.customerId && scope.customerId != types.id.nullUid) {
51 - promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false); 51 + promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false, {ignoreLoading: true});
52 } else { 52 } else {
53 promise = $q.when({data: []}); 53 promise = $q.when({data: []});
54 } 54 }
55 } else { 55 } else {
56 - promise = dashboardService.getTenantDashboards(pageLink, false); 56 + promise = dashboardService.getTenantDashboards(pageLink, false, {ignoreLoading: true});
57 } 57 }
58 58
59 promise.then(function success(result) { 59 promise.then(function success(result) {
@@ -43,7 +43,7 @@ function DatakeyConfigDialogController($scope, $mdDialog, $q, entityService, dat @@ -43,7 +43,7 @@ function DatakeyConfigDialogController($scope, $mdDialog, $q, entityService, dat
43 function success(aliasInfo) { 43 function success(aliasInfo) {
44 var entity = aliasInfo.currentEntity; 44 var entity = aliasInfo.currentEntity;
45 if (entity) { 45 if (entity) {
46 - entityService.getEntityKeys(entity.entityType, entity.id, query, type).then( 46 + entityService.getEntityKeys(entity.entityType, entity.id, query, type, {ignoreLoading: true}).then(
47 function success(keys) { 47 function success(keys) {
48 deferred.resolve(keys); 48 deferred.resolve(keys);
49 }, 49 },
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <tb-datakey-config ng-model="vm.dataKey" 32 <tb-datakey-config ng-model="vm.dataKey"
33 fetch-entity-keys="vm.fetchEntityKeys(entityAliasId, query, type)" 33 fetch-entity-keys="vm.fetchEntityKeys(entityAliasId, query, type)"
@@ -37,10 +37,10 @@ @@ -37,10 +37,10 @@
37 </md-dialog-content> 37 </md-dialog-content>
38 <md-dialog-actions layout="row"> 38 <md-dialog-actions layout="row">
39 <span flex></span> 39 <span flex></span>
40 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 40 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
41 {{ 'action.save' | translate }} 41 {{ 'action.save' | translate }}
42 </md-button> 42 </md-button>
43 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 43 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
44 </md-dialog-actions> 44 </md-dialog-actions>
45 </form> 45 </form>
46 </md-dialog> 46 </md-dialog>
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 </div> 35 </div>
36 <section ng-if="!isReadOnly" layout="row" layout-wrap 36 <section ng-if="!isReadOnly" layout="row" layout-wrap
37 class="tb-header-buttons md-fab"> 37 class="tb-header-buttons md-fab">
38 - <md-button ng-show="isEdit" ng-disabled="loading || theForm.$invalid || !theForm.$dirty" 38 + <md-button ng-show="isEdit" ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty"
39 class="tb-btn-header md-accent md-hue-2 md-fab md-fab-bottom-right" 39 class="tb-btn-header md-accent md-hue-2 md-fab md-fab-bottom-right"
40 aria-label="{{ 'action.apply' | translate }}" 40 aria-label="{{ 'action.apply' | translate }}"
41 ng-click="detailsApply()"> 41 ng-click="detailsApply()">
@@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
44 </md-tooltip> 44 </md-tooltip>
45 <ng-md-icon icon="done"></ng-md-icon> 45 <ng-md-icon icon="done"></ng-md-icon>
46 </md-button> 46 </md-button>
47 - <md-button ng-disabled="loading || (isAlwaysEdit && !theForm.$dirty)" class="tb-btn-header md-accent md-hue-2 md-fab md-fab-bottom-right" 47 + <md-button ng-disabled="$root.loading || (isAlwaysEdit && !theForm.$dirty)" class="tb-btn-header md-accent md-hue-2 md-fab md-fab-bottom-right"
48 aria-label="{{ 'details.edit-mode' | translate }}" 48 aria-label="{{ 'details.edit-mode' | translate }}"
49 ng-click="toggleDetailsEditMode()"> 49 ng-click="toggleDetailsEditMode()">
50 <md-tooltip md-direction="top"> 50 <md-tooltip md-direction="top">
@@ -45,7 +45,7 @@ @@ -45,7 +45,7 @@
45 <tb-grid-card-content flex grid-ctl="vm" parent-ctl="vm.parentCtl" item-controller="vm.itemCardController" item-template="vm.itemCardTemplate" item="rowItem[n]"></tb-grid-card-content> 45 <tb-grid-card-content flex grid-ctl="vm" parent-ctl="vm.parentCtl" item-controller="vm.itemCardController" item-template="vm.itemCardTemplate" item="rowItem[n]"></tb-grid-card-content>
46 </md-card-content> 46 </md-card-content>
47 <md-card-actions layout="row" layout-align="end end"> 47 <md-card-actions layout="row" layout-align="end end">
48 - <md-button ng-if="action.isEnabled(rowItem[n])" ng-disabled="loading" class="md-icon-button md-primary" ng-repeat="action in vm.actionsList" 48 + <md-button ng-if="action.isEnabled(rowItem[n])" ng-disabled="$root.loading" class="md-icon-button md-primary" ng-repeat="action in vm.actionsList"
49 ng-click="action.onAction($event, rowItem[n])" aria-label="{{ action.name() }}"> 49 ng-click="action.onAction($event, rowItem[n])" aria-label="{{ action.name() }}">
50 <md-tooltip md-direction="top"> 50 <md-tooltip md-direction="top">
51 {{ action.details( rowItem[n] ) }} 51 {{ action.details( rowItem[n] ) }}
@@ -81,28 +81,28 @@ @@ -81,28 +81,28 @@
81 </section> 81 </section>
82 82
83 <section layout="row" layout-wrap class="tb-footer-buttons md-fab " layout-align="start end"> 83 <section layout="row" layout-wrap class="tb-footer-buttons md-fab " layout-align="start end">
84 - <md-button ng-disabled="loading" ng-show="vm.items.selectedCount > 0" class="tb-btn-footer md-accent md-hue-2 md-fab" ng-repeat="groupAction in vm.groupActionsList" 84 + <md-button ng-disabled="$root.loading" ng-show="vm.items.selectedCount > 0" class="tb-btn-footer md-accent md-hue-2 md-fab" ng-repeat="groupAction in vm.groupActionsList"
85 ng-click="groupAction.onAction($event, vm.items)" aria-label="{{ groupAction.name() }}"> 85 ng-click="groupAction.onAction($event, vm.items)" aria-label="{{ groupAction.name() }}">
86 <md-tooltip md-direction="top"> 86 <md-tooltip md-direction="top">
87 {{ groupAction.details(vm.items.selectedCount) }} 87 {{ groupAction.details(vm.items.selectedCount) }}
88 </md-tooltip> 88 </md-tooltip>
89 <ng-md-icon icon="{{groupAction.icon}}"></ng-md-icon> 89 <ng-md-icon icon="{{groupAction.icon}}"></ng-md-icon>
90 </md-button> 90 </md-button>
91 - <md-button ng-disabled="loading" ng-show="vm.topIndex > 0" class="tb-btn-footer md-primary md-hue-1 md-fab" ng-click="vm.moveToTop()" aria-label="{{'grid.scroll-to-top' | translate}}" > 91 + <md-button ng-disabled="$root.loading" ng-show="vm.topIndex > 0" class="tb-btn-footer md-primary md-hue-1 md-fab" ng-click="vm.moveToTop()" aria-label="{{'grid.scroll-to-top' | translate}}" >
92 <md-tooltip md-direction="top"> 92 <md-tooltip md-direction="top">
93 {{'grid.scroll-to-top' | translate}} 93 {{'grid.scroll-to-top' | translate}}
94 </md-tooltip> 94 </md-tooltip>
95 <ng-md-icon icon="arrow_drop_up"></ng-md-icon> 95 <ng-md-icon icon="arrow_drop_up"></ng-md-icon>
96 </md-button> 96 </md-button>
97 - <md-button ng-disabled="loading" ng-if="vm.addItemAction.name() && vm.addItemActions.length == 0" class="tb-btn-footer md-accent md-hue-2 md-fab" ng-click="vm.addItemAction.onAction($event)" aria-label="{{ vm.addItemAction.name() }}" > 97 + <md-button ng-disabled="$root.loading" ng-if="vm.addItemAction.name() && vm.addItemActions.length == 0" class="tb-btn-footer md-accent md-hue-2 md-fab" ng-click="vm.addItemAction.onAction($event)" aria-label="{{ vm.addItemAction.name() }}" >
98 <md-tooltip md-direction="top"> 98 <md-tooltip md-direction="top">
99 {{ vm.addItemAction.details() }} 99 {{ vm.addItemAction.details() }}
100 </md-tooltip> 100 </md-tooltip>
101 <ng-md-icon icon="{{ vm.addItemAction.icon }}"></ng-md-icon> 101 <ng-md-icon icon="{{ vm.addItemAction.icon }}"></ng-md-icon>
102 </md-button> 102 </md-button>
103 - <md-fab-speed-dial ng-disabled="loading" ng-if="vm.addItemAction.name() && vm.addItemActions.length > 0" md-open="vm.addItemActionsOpen" class="md-scale" md-direction="up" ng-if="vm.addItemAction.name()"> 103 + <md-fab-speed-dial ng-disabled="$root.loading" ng-if="vm.addItemAction.name() && vm.addItemActions.length > 0" md-open="vm.addItemActionsOpen" class="md-scale" md-direction="up" ng-if="vm.addItemAction.name()">
104 <md-fab-trigger> 104 <md-fab-trigger>
105 - <md-button ng-disabled="loading" class="tb-btn-footer md-accent md-hue-2 md-fab" aria-label="{{ vm.addItemAction.name() }}" > 105 + <md-button ng-disabled="$root.loading" class="tb-btn-footer md-accent md-hue-2 md-fab" aria-label="{{ vm.addItemAction.name() }}" >
106 <md-tooltip md-direction="top"> 106 <md-tooltip md-direction="top">
107 {{ vm.addItemAction.details() }} 107 {{ vm.addItemAction.details() }}
108 </md-tooltip> 108 </md-tooltip>
@@ -110,7 +110,7 @@ @@ -110,7 +110,7 @@
110 </md-button> 110 </md-button>
111 </md-fab-trigger> 111 </md-fab-trigger>
112 <md-fab-actions> 112 <md-fab-actions>
113 - <md-button ng-disabled="loading" class="md-accent md-hue-2 md-fab" ng-repeat="addItemAction in vm.addItemActions" 113 + <md-button ng-disabled="$root.loading" class="md-accent md-hue-2 md-fab" ng-repeat="addItemAction in vm.addItemActions"
114 ng-click="addItemAction.onAction($event)" aria-label="{{ addItemAction.name() }}" > 114 ng-click="addItemAction.onAction($event)" aria-label="{{ addItemAction.name() }}" >
115 <md-tooltip md-direction="top"> 115 <md-tooltip md-direction="top">
116 {{ addItemAction.details() }} 116 {{ addItemAction.details() }}
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 --> 17 -->
18 <form name="theForm" ng-submit="vm.update()"> 18 <form name="theForm" ng-submit="vm.update()">
19 - <fieldset ng-disabled="loading"> 19 + <fieldset ng-disabled="$root.loading">
20 <md-content style="height: 100%" flex layout="column"> 20 <md-content style="height: 100%" flex layout="column">
21 <section layout="column"> 21 <section layout="column">
22 <md-content class="md-padding" layout="column"> 22 <md-content class="md-padding" layout="column">
@@ -32,15 +32,15 @@ @@ -32,15 +32,15 @@
32 </md-button> 32 </md-button>
33 </div> 33 </div>
34 </md-toolbar> 34 </md-toolbar>
35 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
36 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 35 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  36 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
37 <div class="tb-absolute-fill tb-icons-load" ng-show="vm.loadingIcons" layout="column" layout-align="center center"> 37 <div class="tb-absolute-fill tb-icons-load" ng-show="vm.loadingIcons" layout="column" layout-align="center center">
38 <md-progress-circular md-mode="indeterminate" ng-disabled="!vm.loadingIcons" class="md-accent" md-diameter="40"></md-progress-circular> 38 <md-progress-circular md-mode="indeterminate" ng-disabled="!vm.loadingIcons" class="md-accent" md-diameter="40"></md-progress-circular>
39 </div> 39 </div>
40 <md-dialog-content> 40 <md-dialog-content>
41 <div class="md-dialog-content"> 41 <div class="md-dialog-content">
42 <md-content class="md-padding" layout="column"> 42 <md-content class="md-padding" layout="column">
43 - <fieldset ng-disabled="loading"> 43 + <fieldset ng-disabled="$root.loading">
44 <md-button ng-class="{'md-primary md-raised': icon == vm.selectedIcon}" class="tb-select-icon-button md-icon-button" 44 <md-button ng-class="{'md-primary md-raised': icon == vm.selectedIcon}" class="tb-select-icon-button md-icon-button"
45 ng-repeat="icon in vm.icons" ng-click="vm.selectIcon($event, icon)" tb-on-finish-render="iconsLoadFinished"> 45 ng-repeat="icon in vm.icons" ng-click="vm.selectIcon($event, icon)" tb-on-finish-render="iconsLoadFinished">
46 <md-icon class="material-icons">{{icon}}</md-icon> 46 <md-icon class="material-icons">{{icon}}</md-icon>
@@ -54,7 +54,7 @@ @@ -54,7 +54,7 @@
54 </md-dialog-content> 54 </md-dialog-content>
55 <md-dialog-actions layout="row"> 55 <md-dialog-actions layout="row">
56 <span flex></span> 56 <span flex></span>
57 - <md-button ng-disabled="loading" ng-click="vm.cancel()"> 57 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()">
58 {{ 'action.cancel' | translate }} 58 {{ 'action.cancel' | translate }}
59 </md-button> 59 </md-button>
60 </md-dialog-actions> 60 </md-dialog-actions>
@@ -56,7 +56,7 @@ function PluginSelect($compile, $templateCache, $q, pluginService, types) { @@ -56,7 +56,7 @@ function PluginSelect($compile, $templateCache, $q, pluginService, types) {
56 56
57 var deferred = $q.defer(); 57 var deferred = $q.defer();
58 58
59 - scope.pluginFetchFunction(pageLink).then(function success(result) { 59 + scope.pluginFetchFunction(pageLink, {ignoreLoading: true}).then(function success(result) {
60 deferred.resolve(result.data); 60 deferred.resolve(result.data);
61 }, function fail() { 61 }, function fail() {
62 deferred.reject(); 62 deferred.reject();
@@ -89,7 +89,7 @@ function PluginSelect($compile, $templateCache, $q, pluginService, types) { @@ -89,7 +89,7 @@ function PluginSelect($compile, $templateCache, $q, pluginService, types) {
89 89
90 if (scope.selectFirstPlugin) { 90 if (scope.selectFirstPlugin) {
91 var pageLink = {limit: 1, textSearch: ''}; 91 var pageLink = {limit: 1, textSearch: ''};
92 - scope.pluginFetchFunction(pageLink).then(function success(result) { 92 + scope.pluginFetchFunction(pageLink, {ignoreLoading: true}).then(function success(result) {
93 var plugins = result.data; 93 var plugins = result.data;
94 if (plugins.length > 0) { 94 if (plugins.length > 0) {
95 scope.plugin = plugins[0]; 95 scope.plugin = plugins[0];
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 --> 17 -->
18 <form name="theForm" ng-submit="vm.update()"> 18 <form name="theForm" ng-submit="vm.update()">
19 - <fieldset ng-disabled="loading"> 19 + <fieldset ng-disabled="$root.loading">
20 <md-content style="height: 100%" flex layout="column"> 20 <md-content style="height: 100%" flex layout="column">
21 <section layout="column"> 21 <section layout="column">
22 <md-tabs ng-class="{'tb-headless': vm.historyOnly}" md-dynamic-height md-selected="vm.timewindow.selectedTab" md-border-bottom> 22 <md-tabs ng-class="{'tb-headless': vm.historyOnly}" md-dynamic-height md-selected="vm.timewindow.selectedTab" md-border-bottom>
@@ -81,10 +81,10 @@ @@ -81,10 +81,10 @@
81 <span flex></span> 81 <span flex></span>
82 <section layout="row" layout-alignment="start center"> 82 <section layout="row" layout-alignment="start center">
83 <span flex></span> 83 <span flex></span>
84 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 84 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
85 {{ 'action.update' | translate }} 85 {{ 'action.update' | translate }}
86 </md-button> 86 </md-button>
87 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;"> 87 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">
88 {{ 'action.cancel' | translate }} 88 {{ 'action.cancel' | translate }}
89 </md-button> 89 </md-button>
90 </section> 90 </section>
@@ -26,12 +26,12 @@ @@ -26,12 +26,12 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <md-content class="md-padding" layout="column"> 33 <md-content class="md-padding" layout="column">
34 - <fieldset ng-disabled="loading" layout="column"> 34 + <fieldset ng-disabled="$root.loading" layout="column">
35 <md-input-container class="md-block"> 35 <md-input-container class="md-block">
36 <label translate>widget-config.action-source</label> 36 <label translate>widget-config.action-source</label>
37 <md-select name="actionSource" required aria-label="{{ 'widget-config.action-source' | translate }}" ng-model="vm.action.actionSourceId"> 37 <md-select name="actionSource" required aria-label="{{ 'widget-config.action-source' | translate }}" ng-model="vm.action.actionSourceId">
@@ -120,7 +120,7 @@ @@ -120,7 +120,7 @@
120 </div> 120 </div>
121 <tb-js-func ng-if="vm.action.type == vm.types.widgetActionTypes.custom.value" 121 <tb-js-func ng-if="vm.action.type == vm.types.widgetActionTypes.custom.value"
122 ng-model="vm.action.customFunction" 122 ng-model="vm.action.customFunction"
123 - function-args="{{ ['$event', 'widgetContext', 'entityId'] }}" 123 + function-args="{{ ['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams'] }}"
124 validation-args="{{ [] }}"> 124 validation-args="{{ [] }}">
125 </tb-js-func> 125 </tb-js-func>
126 </fieldset> 126 </fieldset>
@@ -129,11 +129,11 @@ @@ -129,11 +129,11 @@
129 </md-dialog-content> 129 </md-dialog-content>
130 <md-dialog-actions layout="row"> 130 <md-dialog-actions layout="row">
131 <span flex></span> 131 <span flex></span>
132 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" 132 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit"
133 class="md-raised md-primary"> 133 class="md-raised md-primary">
134 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} 134 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }}
135 </md-button> 135 </md-button>
136 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;"> 136 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">
137 {{ 'action.cancel' | translate }} 137 {{ 'action.cancel' | translate }}
138 </md-button> 138 </md-button>
139 </md-dialog-actions> 139 </md-dialog-actions>
@@ -104,7 +104,7 @@ @@ -104,7 +104,7 @@
104 generate-data-key="generateDataKey(chip,type)" 104 generate-data-key="generateDataKey(chip,type)"
105 fetch-entity-keys="fetchEntityKeys({entityAliasId: entityAliasId, query: query, type: type})" 105 fetch-entity-keys="fetchEntityKeys({entityAliasId: entityAliasId, query: query, type: type})"
106 on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias})"></tb-datasource> 106 on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias})"></tb-datasource>
107 - <md-button ng-disabled="loading" class="md-icon-button md-primary" 107 + <md-button ng-disabled="$root.loading" class="md-icon-button md-primary"
108 style="min-width: 40px;" 108 style="min-width: 40px;"
109 ng-click="removeDatasource($event, datasource)" 109 ng-click="removeDatasource($event, datasource)"
110 aria-label="{{ 'action.remove' | translate }}"> 110 aria-label="{{ 'action.remove' | translate }}">
@@ -121,7 +121,7 @@ @@ -121,7 +121,7 @@
121 </div> 121 </div>
122 </div> 122 </div>
123 <div flex layout="row" layout-align="start center"> 123 <div flex layout="row" layout-align="start center">
124 - <md-button ng-show="typeParameters.maxDatasources == -1 || datasources.length < typeParameters.maxDatasources" ng-disabled="loading" class="md-primary md-raised" 124 + <md-button ng-show="typeParameters.maxDatasources == -1 || datasources.length < typeParameters.maxDatasources" ng-disabled="$root.loading" class="md-primary md-raised"
125 ng-click="addDatasource($event)" aria-label="{{ 'action.add' | translate }}"> 125 ng-click="addDatasource($event)" aria-label="{{ 'action.add' | translate }}">
126 <md-tooltip md-direction="top"> 126 <md-tooltip md-direction="top">
127 {{ 'widget-config.add-datasource' | translate }} 127 {{ 'widget-config.add-datasource' | translate }}
@@ -444,7 +444,7 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele @@ -444,7 +444,7 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele
444 } 444 }
445 } 445 }
446 446
447 - function handleWidgetAction($event, descriptor, entityId, entityName) { 447 + function handleWidgetAction($event, descriptor, entityId, entityName, additionalParams) {
448 var type = descriptor.type; 448 var type = descriptor.type;
449 var targetEntityParamName = descriptor.stateEntityParamName; 449 var targetEntityParamName = descriptor.stateEntityParamName;
450 var targetEntityId; 450 var targetEntityId;
@@ -485,8 +485,11 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele @@ -485,8 +485,11 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele
485 var customFunction = descriptor.customFunction; 485 var customFunction = descriptor.customFunction;
486 if (angular.isDefined(customFunction) && customFunction.length > 0) { 486 if (angular.isDefined(customFunction) && customFunction.length > 0) {
487 try { 487 try {
488 - var customActionFunction = new Function('$event', 'widgetContext', 'entityId', 'entityName', customFunction);  
489 - customActionFunction($event, widgetContext, entityId, entityName); 488 + if (!additionalParams) {
  489 + additionalParams = {};
  490 + }
  491 + var customActionFunction = new Function('$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', customFunction);
  492 + customActionFunction($event, widgetContext, entityId, entityName, additionalParams);
490 } catch (e) { 493 } catch (e) {
491 // 494 //
492 } 495 }
@@ -48,7 +48,7 @@ function WidgetsBundleSelect($compile, $templateCache, widgetService, types) { @@ -48,7 +48,7 @@ function WidgetsBundleSelect($compile, $templateCache, widgetService, types) {
48 } 48 }
49 } 49 }
50 50
51 - widgetsBundleFetchFunction().then( 51 + widgetsBundleFetchFunction({ignoreLoading: true}).then(
52 function success(widgetsBundles) { 52 function success(widgetsBundles) {
53 scope.widgetsBundles = widgetsBundles; 53 scope.widgetsBundles = widgetsBundles;
54 if (scope.selectFirstBundle) { 54 if (scope.selectFirstBundle) {
@@ -27,8 +27,8 @@ @@ -27,8 +27,8 @@
27 </md-button> 27 </md-button>
28 </div> 28 </div>
29 </md-toolbar> 29 </md-toolbar>
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
31 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 30 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  31 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
32 <md-dialog-content> 32 <md-dialog-content>
33 <div class="md-dialog-content"> 33 <div class="md-dialog-content">
34 <tb-customer customer="vm.item" is-edit="true" the-form="theForm"></tb-customer> 34 <tb-customer customer="vm.item" is-edit="true" the-form="theForm"></tb-customer>
@@ -36,10 +36,10 @@ @@ -36,10 +36,10 @@
36 </md-dialog-content> 36 </md-dialog-content>
37 <md-dialog-actions layout="row"> 37 <md-dialog-actions layout="row">
38 <span flex></span> 38 <span flex></span>
39 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 39 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
40 {{ 'action.add' | translate }} 40 {{ 'action.add' | translate }}
41 </md-button> 41 </md-button>
42 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 42 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
43 </md-dialog-actions> 43 </md-dialog-actions>
44 </form> 44 </form>
45 </md-dialog> 45 </md-dialog>
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 </div> 32 </div>
33 33
34 <md-content class="md-padding" layout="column"> 34 <md-content class="md-padding" layout="column">
35 - <fieldset ng-show="!isPublic" ng-disabled="loading || !isEdit"> 35 + <fieldset ng-show="!isPublic" ng-disabled="$root.loading || !isEdit">
36 <md-input-container class="md-block"> 36 <md-input-container class="md-block">
37 <label translate>customer.title</label> 37 <label translate>customer.title</label>
38 <input required name="title" ng-model="customer.title"> 38 <input required name="title" ng-model="customer.title">
@@ -27,8 +27,8 @@ @@ -27,8 +27,8 @@
27 </md-button> 27 </md-button>
28 </div> 28 </div>
29 </md-toolbar> 29 </md-toolbar>
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
31 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 30 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  31 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
32 <md-dialog-content> 32 <md-dialog-content>
33 <div class="md-dialog-content"> 33 <div class="md-dialog-content">
34 <tb-dashboard-details dashboard="vm.item" is-edit="true" the-form="theForm"></tb-dashboard-details> 34 <tb-dashboard-details dashboard="vm.item" is-edit="true" the-form="theForm"></tb-dashboard-details>
@@ -36,10 +36,10 @@ @@ -36,10 +36,10 @@
36 </md-dialog-content> 36 </md-dialog-content>
37 <md-dialog-actions layout="row"> 37 <md-dialog-actions layout="row">
38 <span flex></span> 38 <span flex></span>
39 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 39 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
40 {{ 'action.add' | translate }} 40 {{ 'action.add' | translate }}
41 </md-button> 41 </md-button>
42 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 42 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
43 </md-dialog-actions> 43 </md-dialog-actions>
44 </form> 44 </form>
45 </md-dialog> 45 </md-dialog>
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <fieldset> 33 <fieldset>
@@ -65,11 +65,11 @@ @@ -65,11 +65,11 @@
65 </md-dialog-content> 65 </md-dialog-content>
66 <md-dialog-actions layout="row"> 66 <md-dialog-actions layout="row">
67 <span flex></span> 67 <span flex></span>
68 - <md-button ng-disabled="loading || vm.dashboards.selectedCount == 0" type="submit" 68 + <md-button ng-disabled="$root.loading || vm.dashboards.selectedCount == 0" type="submit"
69 class="md-raised md-primary"> 69 class="md-raised md-primary">
70 {{ 'action.assign' | translate }} 70 {{ 'action.assign' | translate }}
71 </md-button> 71 </md-button>
72 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 72 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
73 translate }} 73 translate }}
74 </md-button> 74 </md-button>
75 </md-dialog-actions> 75 </md-dialog-actions>
@@ -110,7 +110,7 @@ export default function AddWidgetController($scope, widgetService, entityService @@ -110,7 +110,7 @@ export default function AddWidgetController($scope, widgetService, entityService
110 function success(aliasInfo) { 110 function success(aliasInfo) {
111 var entity = aliasInfo.currentEntity; 111 var entity = aliasInfo.currentEntity;
112 if (entity) { 112 if (entity) {
113 - entityService.getEntityKeys(entity.entityType, entity.id, query, type).then( 113 + entityService.getEntityKeys(entity.entityType, entity.id, query, type, {ignoreLoading: true}).then(
114 function success(keys) { 114 function success(keys) {
115 deferred.resolve(keys); 115 deferred.resolve(keys);
116 }, 116 },
@@ -27,11 +27,11 @@ @@ -27,11 +27,11 @@
27 </md-button> 27 </md-button>
28 </div> 28 </div>
29 </md-toolbar> 29 </md-toolbar>
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
31 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 30 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  31 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
32 <md-dialog-content> 32 <md-dialog-content>
33 <div class="md-dialog-content" style="padding-top: 0px;"> 33 <div class="md-dialog-content" style="padding-top: 0px;">
34 - <fieldset ng-disabled="loading" style="position: relative; height: 600px;"> 34 + <fieldset ng-disabled="$root.loading" style="position: relative; height: 600px;">
35 <tb-widget-config widget-type="vm.widget.type" 35 <tb-widget-config widget-type="vm.widget.type"
36 type-parameters="vm.widgetInfo.typeParameters" 36 type-parameters="vm.widgetInfo.typeParameters"
37 action-sources="vm.widgetInfo.actionSources" 37 action-sources="vm.widgetInfo.actionSources"
@@ -50,11 +50,11 @@ @@ -50,11 +50,11 @@
50 </md-dialog-content> 50 </md-dialog-content>
51 <md-dialog-actions layout="row"> 51 <md-dialog-actions layout="row">
52 <span flex></span> 52 <span flex></span>
53 - <md-button ng-disabled="loading || theForm.$invalid" type="submit" 53 + <md-button ng-disabled="$root.loading || theForm.$invalid" type="submit"
54 class="md-raised md-primary"> 54 class="md-raised md-primary">
55 {{ 'action.add' | translate }} 55 {{ 'action.add' | translate }}
56 </md-button> 56 </md-button>
57 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 57 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
58 translate }} 58 translate }}
59 </md-button> 59 </md-button>
60 </md-dialog-actions> 60 </md-dialog-actions>
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <fieldset> 33 <fieldset>
@@ -65,10 +65,10 @@ @@ -65,10 +65,10 @@
65 </md-dialog-content> 65 </md-dialog-content>
66 <md-dialog-actions layout="row"> 66 <md-dialog-actions layout="row">
67 <span flex></span> 67 <span flex></span>
68 - <md-button ng-disabled="loading || vm.customers.selection==null" type="submit" class="md-raised md-primary"> 68 + <md-button ng-disabled="$root.loading || vm.customers.selection==null" type="submit" class="md-raised md-primary">
69 {{ 'action.assign' | translate }} 69 {{ 'action.assign' | translate }}
70 </md-button> 70 </md-button>
71 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 71 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
72 translate }} 72 translate }}
73 </md-button> 73 </md-button>
74 </md-dialog-actions> 74 </md-dialog-actions>
@@ -59,7 +59,7 @@ @@ -59,7 +59,7 @@
59 </md-button> 59 </md-button>
60 </div> 60 </div>
61 </div> 61 </div>
62 - <fieldset ng-disabled="loading || !isEdit"> 62 + <fieldset ng-disabled="$root.loading || !isEdit">
63 <md-input-container class="md-block"> 63 <md-input-container class="md-block">
64 <label translate>dashboard.title</label> 64 <label translate>dashboard.title</label>
65 <input required name="title" ng-model="dashboard.title"> 65 <input required name="title" ng-model="dashboard.title">
@@ -26,11 +26,11 @@ @@ -26,11 +26,11 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading"> 33 + <fieldset ng-disabled="$root.loading">
34 <div ng-show="vm.settings"> 34 <div ng-show="vm.settings">
35 <md-input-container class="md-block"> 35 <md-input-container class="md-block">
36 <label translate>dashboard.state-controller</label> 36 <label translate>dashboard.state-controller</label>
@@ -194,10 +194,10 @@ @@ -194,10 +194,10 @@
194 </md-dialog-content> 194 </md-dialog-content>
195 <md-dialog-actions layout="row"> 195 <md-dialog-actions layout="row">
196 <span flex></span> 196 <span flex></span>
197 - <md-button ng-disabled="loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary"> 197 + <md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary">
198 {{ 'action.save' | translate }} 198 {{ 'action.save' | translate }}
199 </md-button> 199 </md-button>
200 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 200 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
201 </md-dialog-actions> 201 </md-dialog-actions>
202 </form> 202 </form>
203 </md-dialog> 203 </md-dialog>
@@ -110,7 +110,7 @@ @@ -110,7 +110,7 @@
110 </section> 110 </section>
111 <section class="tb-dashboard-container tb-absolute-fill" 111 <section class="tb-dashboard-container tb-absolute-fill"
112 ng-class="{ 'is-fullscreen': forceFullscreen, 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }"> 112 ng-class="{ 'is-fullscreen': forceFullscreen, 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">
113 - <section ng-show="!loading && vm.dashboardConfigurationError()" layout-align="center center" 113 + <section ng-show="!$root.loading && vm.dashboardConfigurationError()" layout-align="center center"
114 ng-style="{'color': vm.dashboard.configuration.settings.titleColor}" 114 ng-style="{'color': vm.dashboard.configuration.settings.titleColor}"
115 ng-class="{'tb-padded' : !vm.widgetEditMode}" 115 ng-class="{'tb-padded' : !vm.widgetEditMode}"
116 style="text-transform: uppercase; display: flex; z-index: 1;" 116 style="text-transform: uppercase; display: flex; z-index: 1;"
@@ -277,10 +277,10 @@ @@ -277,10 +277,10 @@
277 </div> 277 </div>
278 </tb-details-sidenav> 278 </tb-details-sidenav>
279 <section layout="row" layout-wrap class="tb-footer-buttons md-fab" layout-align="start end"> 279 <section layout="row" layout-wrap class="tb-footer-buttons md-fab" layout-align="start end">
280 - <md-fab-speed-dial ng-disabled="loading" ng-show="!vm.isAddingWidget && vm.isEdit && !vm.widgetEditMode" 280 + <md-fab-speed-dial ng-disabled="$root.loading" ng-show="!vm.isAddingWidget && vm.isEdit && !vm.widgetEditMode"
281 md-open="vm.addItemActionsOpen" class="md-scale" md-direction="up"> 281 md-open="vm.addItemActionsOpen" class="md-scale" md-direction="up">
282 <md-fab-trigger> 282 <md-fab-trigger>
283 - <md-button ng-disabled="loading" 283 + <md-button ng-disabled="$root.loading"
284 class="tb-btn-footer md-accent md-hue-2 md-fab" 284 class="tb-btn-footer md-accent md-hue-2 md-fab"
285 aria-label="{{ 'dashboard.add-widget' | translate }}"> 285 aria-label="{{ 'dashboard.add-widget' | translate }}">
286 <md-tooltip md-direction="top"> 286 <md-tooltip md-direction="top">
@@ -290,7 +290,7 @@ @@ -290,7 +290,7 @@
290 </md-button> 290 </md-button>
291 </md-fab-trigger> 291 </md-fab-trigger>
292 <md-fab-actions> 292 <md-fab-actions>
293 - <md-button ng-disabled="loading" 293 + <md-button ng-disabled="$root.loading"
294 class="tmd-accent md-hue-2 md-fab" ng-click="vm.addWidget($event)" 294 class="tmd-accent md-hue-2 md-fab" ng-click="vm.addWidget($event)"
295 aria-label="{{ 'action.create' | translate }}"> 295 aria-label="{{ 'action.create' | translate }}">
296 <md-tooltip md-direction="top"> 296 <md-tooltip md-direction="top">
@@ -298,7 +298,7 @@ @@ -298,7 +298,7 @@
298 </md-tooltip> 298 </md-tooltip>
299 <ng-md-icon icon="insert_drive_file"></ng-md-icon> 299 <ng-md-icon icon="insert_drive_file"></ng-md-icon>
300 </md-button> 300 </md-button>
301 - <md-button ng-disabled="loading" 301 + <md-button ng-disabled="$root.loading"
302 class="tmd-accent md-hue-2 md-fab" ng-click="vm.importWidget($event)" 302 class="tmd-accent md-hue-2 md-fab" ng-click="vm.importWidget($event)"
303 aria-label="{{ 'action.import' | translate }}"> 303 aria-label="{{ 'action.import' | translate }}">
304 <md-tooltip md-direction="top"> 304 <md-tooltip md-direction="top">
@@ -308,7 +308,7 @@ @@ -308,7 +308,7 @@
308 </md-button> 308 </md-button>
309 </md-fab-actions> 309 </md-fab-actions>
310 </md-fab-speed-dial> 310 </md-fab-speed-dial>
311 - <md-button ng-if="(vm.isTenantAdmin() || vm.isSystemAdmin()) && !forceFullscreen" ng-show="vm.isEdit && !vm.isAddingWidget && !loading" ng-disabled="loading" 311 + <md-button ng-if="(vm.isTenantAdmin() || vm.isSystemAdmin()) && !forceFullscreen" ng-show="vm.isEdit && !vm.isAddingWidget && !$root.loading" ng-disabled="$root.loading"
312 class="tb-btn-footer md-accent md-hue-2 md-fab" 312 class="tb-btn-footer md-accent md-hue-2 md-fab"
313 aria-label="{{ 'action.apply' | translate }}" 313 aria-label="{{ 'action.apply' | translate }}"
314 ng-click="vm.saveDashboard()"> 314 ng-click="vm.saveDashboard()">
@@ -317,8 +317,8 @@ @@ -317,8 +317,8 @@
317 </md-tooltip> 317 </md-tooltip>
318 <ng-md-icon icon="done"></ng-md-icon> 318 <ng-md-icon icon="done"></ng-md-icon>
319 </md-button> 319 </md-button>
320 - <md-button ng-show="!vm.isAddingWidget && !loading"  
321 - ng-if="(vm.isTenantAdmin() || vm.isSystemAdmin()) && !forceFullscreen" ng-disabled="loading" 320 + <md-button ng-show="!vm.isAddingWidget && !$root.loading"
  321 + ng-if="(vm.isTenantAdmin() || vm.isSystemAdmin()) && !forceFullscreen" ng-disabled="$root.loading"
322 class="tb-btn-footer md-accent md-hue-2 md-fab" 322 class="tb-btn-footer md-accent md-hue-2 md-fab"
323 aria-label="{{ 'action.edit-mode' | translate }}" 323 aria-label="{{ 'action.edit-mode' | translate }}"
324 ng-click="vm.toggleDashboardEditMode()"> 324 ng-click="vm.toggleDashboardEditMode()">
@@ -75,7 +75,7 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid @@ -75,7 +75,7 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid
75 function success(aliasInfo) { 75 function success(aliasInfo) {
76 var entity = aliasInfo.currentEntity; 76 var entity = aliasInfo.currentEntity;
77 if (entity) { 77 if (entity) {
78 - entityService.getEntityKeys(entity.entityType, entity.id, query, type).then( 78 + entityService.getEntityKeys(entity.entityType, entity.id, query, type, {ignoreLoading: true}).then(
79 function success(keys) { 79 function success(keys) {
80 deferred.resolve(keys); 80 deferred.resolve(keys);
81 }, 81 },
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 limitations under the License. 15 limitations under the License.
16 16
17 --> 17 -->
18 -<fieldset ng-disabled="loading"> 18 +<fieldset ng-disabled="$root.loading">
19 <tb-widget-config widget-type="widget.type" 19 <tb-widget-config widget-type="widget.type"
20 type-parameters="typeParameters" 20 type-parameters="typeParameters"
21 action-sources="actionSources" 21 action-sources="actionSources"
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 'background-attachment': 'scroll', 22 'background-attachment': 'scroll',
23 'background-size': vm.layoutCtx.gridSettings.backgroundSizeMode || '100%', 23 'background-size': vm.layoutCtx.gridSettings.backgroundSizeMode || '100%',
24 'background-position': '0% 0%'}"> 24 'background-position': '0% 0%'}">
25 - <section ng-show="!loading && vm.noData()" layout-align="center center" 25 + <section ng-show="!$root.loading && vm.noData()" layout-align="center center"
26 ng-style="{'color': vm.layoutCtx.gridSettings.color}" 26 ng-style="{'color': vm.layoutCtx.gridSettings.color}"
27 style="text-transform: uppercase; display: flex; z-index: 1; pointer-events: none;" 27 style="text-transform: uppercase; display: flex; z-index: 1; pointer-events: none;"
28 class="md-headline tb-absolute-fill"> 28 class="md-headline tb-absolute-fill">
@@ -26,11 +26,11 @@ @@ -26,11 +26,11 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading"> 33 + <fieldset ng-disabled="$root.loading">
34 <div layout="row" layout-align="start center"> 34 <div layout="row" layout-align="start center">
35 <md-checkbox ng-disabled="true" flex aria-label="{{ 'layout.main' | translate }}" 35 <md-checkbox ng-disabled="true" flex aria-label="{{ 'layout.main' | translate }}"
36 ng-model="vm.displayLayouts.main">{{ 'layout.main' | translate }} 36 ng-model="vm.displayLayouts.main">{{ 'layout.main' | translate }}
@@ -56,10 +56,10 @@ @@ -56,10 +56,10 @@
56 </md-dialog-content> 56 </md-dialog-content>
57 <md-dialog-actions layout="row"> 57 <md-dialog-actions layout="row">
58 <span flex></span> 58 <span flex></span>
59 - <md-button ng-disabled="loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary"> 59 + <md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary">
60 {{ 'action.save' | translate }} 60 {{ 'action.save' | translate }}
61 </md-button> 61 </md-button>
62 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 62 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
63 </md-dialog-actions> 63 </md-dialog-actions>
64 </form> 64 </form>
65 </md-dialog> 65 </md-dialog>
@@ -26,11 +26,11 @@ @@ -26,11 +26,11 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading"> 33 + <fieldset ng-disabled="$root.loading">
34 <div layout="row" layout-align="start center"> 34 <div layout="row" layout-align="start center">
35 <md-button flex class="tb-layout-button md-raised md-primary" layout="column" 35 <md-button flex class="tb-layout-button md-raised md-primary" layout="column"
36 ng-click="vm.selectLayout($event, 'main')"> 36 ng-click="vm.selectLayout($event, 'main')">
@@ -26,12 +26,12 @@ @@ -26,12 +26,12 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <md-content class="md-padding" layout="column"> 33 <md-content class="md-padding" layout="column">
34 - <fieldset ng-disabled="loading"> 34 + <fieldset ng-disabled="$root.loading">
35 <md-input-container class="md-block"> 35 <md-input-container class="md-block">
36 <label translate>dashboard.state-name</label> 36 <label translate>dashboard.state-name</label>
37 <input name="name" required ng-model="vm.state.name"> 37 <input name="name" required ng-model="vm.state.name">
@@ -57,11 +57,11 @@ @@ -57,11 +57,11 @@
57 </md-dialog-content> 57 </md-dialog-content>
58 <md-dialog-actions layout="row"> 58 <md-dialog-actions layout="row">
59 <span flex></span> 59 <span flex></span>
60 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" 60 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit"
61 class="md-raised md-primary"> 61 class="md-raised md-primary">
62 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} 62 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }}
63 </md-button> 63 </md-button>
64 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;"> 64 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">
65 {{ 'action.cancel' | translate }} 65 {{ 'action.cancel' | translate }}
66 </md-button> 66 </md-button>
67 </md-dialog-actions> 67 </md-dialog-actions>
@@ -26,11 +26,11 @@ @@ -26,11 +26,11 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading"> 33 + <fieldset ng-disabled="$root.loading">
34 <div class="manage-dashboard-states" layout="column"> 34 <div class="manage-dashboard-states" layout="column">
35 <md-toolbar class="md-table-toolbar md-default" ng-show="vm.query.search === null"> 35 <md-toolbar class="md-table-toolbar md-default" ng-show="vm.query.search === null">
36 <div class="md-toolbar-tools"> 36 <div class="md-toolbar-tools">
@@ -118,10 +118,10 @@ @@ -118,10 +118,10 @@
118 </md-dialog-content> 118 </md-dialog-content>
119 <md-dialog-actions layout="row"> 119 <md-dialog-actions layout="row">
120 <span flex></span> 120 <span flex></span>
121 - <md-button ng-disabled="loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary"> 121 + <md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary">
122 {{ 'action.save' | translate }} 122 {{ 'action.save' | translate }}
123 </md-button> 123 </md-button>
124 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 124 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
125 </md-dialog-actions> 125 </md-dialog-actions>
126 </form> 126 </form>
127 </md-dialog> 127 </md-dialog>
@@ -26,11 +26,11 @@ @@ -26,11 +26,11 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading"> 33 + <fieldset ng-disabled="$root.loading">
34 <md-select required aria-label="{{ 'dashboard.state' | translate }}" ng-model="vm.stateId"> 34 <md-select required aria-label="{{ 'dashboard.state' | translate }}" ng-model="vm.stateId">
35 <md-option ng-repeat="(stateId, state) in vm.states" ng-value="stateId"> 35 <md-option ng-repeat="(stateId, state) in vm.states" ng-value="stateId">
36 {{state.name}} 36 {{state.name}}
@@ -41,10 +41,10 @@ @@ -41,10 +41,10 @@
41 </md-dialog-content> 41 </md-dialog-content>
42 <md-dialog-actions layout="row"> 42 <md-dialog-actions layout="row">
43 <span flex></span> 43 <span flex></span>
44 - <md-button ng-disabled="loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary"> 44 + <md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid" type="submit" class="md-raised md-primary">
45 {{ 'action.save' | translate }} 45 {{ 'action.save' | translate }}
46 </md-button> 46 </md-button>
47 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 47 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
48 </md-dialog-actions> 48 </md-dialog-actions>
49 </form> 49 </form>
50 </md-dialog> 50 </md-dialog>
@@ -27,8 +27,8 @@ @@ -27,8 +27,8 @@
27 </md-button> 27 </md-button>
28 </div> 28 </div>
29 </md-toolbar> 29 </md-toolbar>
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
31 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 30 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  31 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
32 <md-dialog-content> 32 <md-dialog-content>
33 <div class="md-dialog-content"> 33 <div class="md-dialog-content">
34 <tb-device device="vm.item" is-edit="true" the-form="theForm"></tb-device> 34 <tb-device device="vm.item" is-edit="true" the-form="theForm"></tb-device>
@@ -36,10 +36,10 @@ @@ -36,10 +36,10 @@
36 </md-dialog-content> 36 </md-dialog-content>
37 <md-dialog-actions layout="row"> 37 <md-dialog-actions layout="row">
38 <span flex></span> 38 <span flex></span>
39 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 39 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
40 {{ 'action.add' | translate }} 40 {{ 'action.add' | translate }}
41 </md-button> 41 </md-button>
42 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 42 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
43 </md-dialog-actions> 43 </md-dialog-actions>
44 </form> 44 </form>
45 </md-dialog> 45 </md-dialog>
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <fieldset> 33 <fieldset>
@@ -65,11 +65,11 @@ @@ -65,11 +65,11 @@
65 </md-dialog-content> 65 </md-dialog-content>
66 <md-dialog-actions layout="row"> 66 <md-dialog-actions layout="row">
67 <span flex></span> 67 <span flex></span>
68 - <md-button ng-disabled="loading || vm.devices.selectedCount == 0" type="submit" 68 + <md-button ng-disabled="$root.loading || vm.devices.selectedCount == 0" type="submit"
69 class="md-raised md-primary"> 69 class="md-raised md-primary">
70 {{ 'action.assign' | translate }} 70 {{ 'action.assign' | translate }}
71 </md-button> 71 </md-button>
72 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 72 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
73 translate }} 73 translate }}
74 </md-button> 74 </md-button>
75 </md-dialog-actions> 75 </md-dialog-actions>
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <fieldset> 33 <fieldset>
@@ -65,10 +65,10 @@ @@ -65,10 +65,10 @@
65 </md-dialog-content> 65 </md-dialog-content>
66 <md-dialog-actions layout="row"> 66 <md-dialog-actions layout="row">
67 <span flex></span> 67 <span flex></span>
68 - <md-button ng-disabled="loading || vm.customers.selection==null" type="submit" class="md-raised md-primary"> 68 + <md-button ng-disabled="$root.loading || vm.customers.selection==null" type="submit" class="md-raised md-primary">
69 {{ 'action.assign' | translate }} 69 {{ 'action.assign' | translate }}
70 </md-button> 70 </md-button>
71 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 71 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
72 translate }} 72 translate }}
73 </md-button> 73 </md-button>
74 </md-dialog-actions> 74 </md-dialog-actions>
@@ -26,14 +26,14 @@ @@ -26,14 +26,14 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading || vm.isReadOnly"> 33 + <fieldset ng-disabled="$root.loading || vm.isReadOnly">
34 <md-input-container class="md-block"> 34 <md-input-container class="md-block">
35 <label translate>device.credentials-type</label> 35 <label translate>device.credentials-type</label>
36 - <md-select ng-disabled="loading || vm.isReadOnly" ng-model="vm.deviceCredentials.credentialsType" 36 + <md-select ng-disabled="$root.loading || vm.isReadOnly" ng-model="vm.deviceCredentials.credentialsType"
37 ng-change="vm.clear()"> 37 ng-change="vm.clear()">
38 <md-option ng-repeat="credentialsType in vm.credentialsTypes" value="{{credentialsType.value}}"> 38 <md-option ng-repeat="credentialsType in vm.credentialsTypes" value="{{credentialsType.value}}">
39 {{credentialsType.name}} 39 {{credentialsType.name}}
@@ -62,10 +62,10 @@ @@ -62,10 +62,10 @@
62 </md-dialog-content> 62 </md-dialog-content>
63 <md-dialog-actions layout="row"> 63 <md-dialog-actions layout="row">
64 <span flex></span> 64 <span flex></span>
65 - <md-button ng-if="!vm.isReadOnly" ng-disabled="loading || theForm.$invalid || !theForm.$dirty || !vm.valid()" type="submit" class="md-raised md-primary"> 65 + <md-button ng-if="!vm.isReadOnly" ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty || !vm.valid()" type="submit" class="md-raised md-primary">
66 {{ 'action.save' | translate }} 66 {{ 'action.save' | translate }}
67 </md-button> 67 </md-button>
68 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ (vm.isReadOnly ? 'action.close' : 'action.cancel') | translate }}</md-button> 68 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ (vm.isReadOnly ? 'action.close' : 'action.cancel') | translate }}</md-button>
69 </md-dialog-actions> 69 </md-dialog-actions>
70 </form> 70 </form>
71 </md-dialog> 71 </md-dialog>
@@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
58 ng-show="!isEdit && isPublic && (deviceScope === 'customer' || deviceScope === 'tenant')"> 58 ng-show="!isEdit && isPublic && (deviceScope === 'customer' || deviceScope === 'tenant')">
59 {{ 'device.device-public' | translate }} 59 {{ 'device.device-public' | translate }}
60 </div> 60 </div>
61 - <fieldset ng-disabled="loading || !isEdit"> 61 + <fieldset ng-disabled="$root.loading || !isEdit">
62 <md-input-container class="md-block"> 62 <md-input-container class="md-block">
63 <label translate>device.name</label> 63 <label translate>device.name</label>
64 <input required name="name" ng-model="device.name"> 64 <input required name="name" ng-model="device.name">
@@ -67,14 +67,14 @@ @@ -67,14 +67,14 @@
67 </div> 67 </div>
68 </md-input-container> 68 </md-input-container>
69 <tb-entity-subtype-autocomplete 69 <tb-entity-subtype-autocomplete
70 - ng-disabled="loading || !isEdit" 70 + ng-disabled="$root.loading || !isEdit"
71 tb-required="true" 71 tb-required="true"
72 the-form="theForm" 72 the-form="theForm"
73 ng-model="device.type" 73 ng-model="device.type"
74 entity-type="types.entityType.device"> 74 entity-type="types.entityType.device">
75 </tb-entity-subtype-autocomplete> 75 </tb-entity-subtype-autocomplete>
76 <md-input-container class="md-block"> 76 <md-input-container class="md-block">
77 - <md-checkbox ng-disabled="loading || !isEdit" flex aria-label="{{ 'device.is-gateway' | translate }}" 77 + <md-checkbox ng-disabled="$root.loading || !isEdit" flex aria-label="{{ 'device.is-gateway' | translate }}"
78 ng-model="device.additionalInfo.gateway">{{ 'device.is-gateway' | translate }} 78 ng-model="device.additionalInfo.gateway">{{ 'device.is-gateway' | translate }}
79 </md-checkbox> 79 </md-checkbox>
80 </md-input-container> 80 </md-input-container>
@@ -26,11 +26,11 @@ @@ -26,11 +26,11 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading"> 33 + <fieldset ng-disabled="$root.loading">
34 <div flex layout="column"> 34 <div flex layout="column">
35 <div layout="row"> 35 <div layout="row">
36 <md-input-container flex class="md-block"> 36 <md-input-container flex class="md-block">
@@ -64,10 +64,10 @@ @@ -64,10 +64,10 @@
64 </md-dialog-content> 64 </md-dialog-content>
65 <md-dialog-actions layout="row"> 65 <md-dialog-actions layout="row">
66 <span flex></span> 66 <span flex></span>
67 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 67 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
68 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} 68 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }}
69 </md-button> 69 </md-button>
70 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 70 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
71 </md-dialog-actions> 71 </md-dialog-actions>
72 </form> 72 </form>
73 </md-dialog> 73 </md-dialog>
@@ -26,8 +26,8 @@ @@ -26,8 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <div class="tb-aliases-header" flex layout="row" layout-align="start center"> 31 <div class="tb-aliases-header" flex layout="row" layout-align="start center">
32 <span flex="5"></span> 32 <span flex="5"></span>
33 <div flex layout="row" layout-align="start center"> 33 <div flex layout="row" layout-align="start center">
@@ -40,7 +40,7 @@ @@ -40,7 +40,7 @@
40 <md-divider></md-divider> 40 <md-divider></md-divider>
41 <md-dialog-content> 41 <md-dialog-content>
42 <div class="md-dialog-content"> 42 <div class="md-dialog-content">
43 - <fieldset ng-disabled="loading"> 43 + <fieldset ng-disabled="$root.loading">
44 <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index"> 44 <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index">
45 <span flex="5">{{$index + 1}}.</span> 45 <span flex="5">{{$index + 1}}.</span>
46 <di class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center"> 46 <di class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center">
@@ -63,7 +63,7 @@ @@ -63,7 +63,7 @@
63 aria-label="resolve-multiple-switcher"> 63 aria-label="resolve-multiple-switcher">
64 </md-switch> 64 </md-switch>
65 </section> 65 </section>
66 - <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;" 66 + <md-button ng-disabled="$root.loading" class="md-icon-button md-primary" style="min-width: 40px;"
67 ng-click="vm.editAlias($event, entityAlias)" aria-label="{{ 'action.edit' | translate }}"> 67 ng-click="vm.editAlias($event, entityAlias)" aria-label="{{ 'action.edit' | translate }}">
68 <md-tooltip md-direction="top"> 68 <md-tooltip md-direction="top">
69 {{ 'alias.edit' | translate }} 69 {{ 'alias.edit' | translate }}
@@ -72,7 +72,7 @@ @@ -72,7 +72,7 @@
72 edit 72 edit
73 </md-icon> 73 </md-icon>
74 </md-button> 74 </md-button>
75 - <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;" 75 + <md-button ng-disabled="$root.loading" class="md-icon-button md-primary" style="min-width: 40px;"
76 ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}"> 76 ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}">
77 <md-tooltip md-direction="top"> 77 <md-tooltip md-direction="top">
78 {{ 'entity.remove-alias' | translate }} 78 {{ 'entity.remove-alias' | translate }}
@@ -87,7 +87,7 @@ @@ -87,7 +87,7 @@
87 </div> 87 </div>
88 </md-dialog-content> 88 </md-dialog-content>
89 <md-dialog-actions layout="row"> 89 <md-dialog-actions layout="row">
90 - <md-button ng-show="!vm.disableAdd" ng-disabled="loading" class="md-primary md-raised" 90 + <md-button ng-show="!vm.disableAdd" ng-disabled="$root.loading" class="md-primary md-raised"
91 ng-click="vm.addAlias($event)" 91 ng-click="vm.addAlias($event)"
92 aria-label="{{ 'alias.add' | translate }}"> 92 aria-label="{{ 'alias.add' | translate }}">
93 <md-tooltip md-direction="top"> 93 <md-tooltip md-direction="top">
@@ -96,10 +96,10 @@ @@ -96,10 +96,10 @@
96 <span translate>alias.add</span> 96 <span translate>alias.add</span>
97 </md-button> 97 </md-button>
98 <span flex></span> 98 <span flex></span>
99 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 99 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
100 {{ 'action.save' | translate }} 100 {{ 'action.save' | translate }}
101 </md-button> 101 </md-button>
102 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 102 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
103 </md-dialog-actions> 103 </md-dialog-actions>
104 </form> 104 </form>
105 </md-dialog> 105 </md-dialog>
@@ -26,12 +26,12 @@ @@ -26,12 +26,12 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <md-content class="md-padding" layout="column"> 33 <md-content class="md-padding" layout="column">
34 - <fieldset ng-disabled="loading"> 34 + <fieldset ng-disabled="$root.loading">
35 <md-input-container class="md-block"> 35 <md-input-container class="md-block">
36 <label translate>attribute.key</label> 36 <label translate>attribute.key</label>
37 <input required name="key" ng-model="vm.attribute.key"> 37 <input required name="key" ng-model="vm.attribute.key">
@@ -42,7 +42,7 @@ @@ -42,7 +42,7 @@
42 <section layout="row"> 42 <section layout="row">
43 <md-input-container flex="40" class="md-block" style="width: 200px;"> 43 <md-input-container flex="40" class="md-block" style="width: 200px;">
44 <label translate>value.type</label> 44 <label translate>value.type</label>
45 - <md-select ng-model="vm.valueType" ng-disabled="loading()"> 45 + <md-select ng-model="vm.valueType" ng-disabled="$root.loading">
46 <md-option ng-repeat="type in vm.valueTypes" ng-value="type"> 46 <md-option ng-repeat="type in vm.valueTypes" ng-value="type">
47 <md-icon md-svg-icon="{{ type.icon }}"></md-icon> 47 <md-icon md-svg-icon="{{ type.icon }}"></md-icon>
48 <span>{{type.name | translate}}</span> 48 <span>{{type.name | translate}}</span>
@@ -83,11 +83,11 @@ @@ -83,11 +83,11 @@
83 </md-dialog-content> 83 </md-dialog-content>
84 <md-dialog-actions layout="row"> 84 <md-dialog-actions layout="row">
85 <span flex></span> 85 <span flex></span>
86 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" 86 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit"
87 class="md-raised md-primary"> 87 class="md-raised md-primary">
88 {{ 'action.add' | translate }} 88 {{ 'action.add' | translate }}
89 </md-button> 89 </md-button>
90 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 90 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
91 translate }} 91 translate }}
92 </md-button> 92 </md-button>
93 </md-dialog-actions> 93 </md-dialog-actions>
@@ -26,18 +26,18 @@ @@ -26,18 +26,18 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <md-content class="md-padding" layout="column"> 33 <md-content class="md-padding" layout="column">
34 - <fieldset ng-disabled="loading"> 34 + <fieldset ng-disabled="$root.loading">
35 <md-radio-group ng-model="vm.addToDashboardType" class="md-primary"> 35 <md-radio-group ng-model="vm.addToDashboardType" class="md-primary">
36 <md-radio-button flex ng-value=0 class="md-primary md-align-top-left md-radio-interactive"> 36 <md-radio-button flex ng-value=0 class="md-primary md-align-top-left md-radio-interactive">
37 <section flex layout="column" style="width: 300px;"> 37 <section flex layout="column" style="width: 300px;">
38 <span translate style="padding-bottom: 10px;">dashboard.select-existing</span> 38 <span translate style="padding-bottom: 10px;">dashboard.select-existing</span>
39 <tb-dashboard-autocomplete the-form="theForm" 39 <tb-dashboard-autocomplete the-form="theForm"
40 - ng-disabled="loading || vm.addToDashboardType != 0" 40 + ng-disabled="$root.loading || vm.addToDashboardType != 0"
41 tb-required="vm.addToDashboardType === 0" 41 tb-required="vm.addToDashboardType === 0"
42 ng-model="vm.dashboardId" 42 ng-model="vm.dashboardId"
43 select-first-dashboard="false"> 43 select-first-dashboard="false">
@@ -69,11 +69,11 @@ @@ -69,11 +69,11 @@
69 style="margin-bottom: 0px; padding-right: 20px;"> 69 style="margin-bottom: 0px; padding-right: 20px;">
70 {{ 'dashboard.open-dashboard' | translate }} 70 {{ 'dashboard.open-dashboard' | translate }}
71 </md-checkbox> 71 </md-checkbox>
72 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" 72 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit"
73 class="md-raised md-primary"> 73 class="md-raised md-primary">
74 {{ 'action.add' | translate }} 74 {{ 'action.add' | translate }}
75 </md-button> 75 </md-button>
76 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 76 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
77 translate }} 77 translate }}
78 </md-button> 78 </md-button>
79 </md-dialog-actions> 79 </md-dialog-actions>
@@ -47,7 +47,7 @@ md-toolbar.md-table-toolbar.alternate { @@ -47,7 +47,7 @@ md-toolbar.md-table-toolbar.alternate {
47 .widgets-carousel { 47 .widgets-carousel {
48 position: relative; 48 position: relative;
49 margin: 0px; 49 margin: 0px;
50 - 50 + height: calc(100% - 100px);
51 min-height: 150px !important; 51 min-height: 150px !important;
52 52
53 tb-dashboard { 53 tb-dashboard {
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 <section ng-show="!disableAttributeScopeSelection"> 19 <section ng-show="!disableAttributeScopeSelection">
20 <md-input-container class="md-block" style="width: 200px;"> 20 <md-input-container class="md-block" style="width: 200px;">
21 <label translate>attribute.attributes-scope</label> 21 <label translate>attribute.attributes-scope</label>
22 - <md-select ng-model="attributeScope" ng-disabled="loading() || attributeScopeSelectionReadonly"> 22 + <md-select ng-model="attributeScope" ng-disabled="$root.loading || attributeScopeSelectionReadonly">
23 <md-option ng-repeat="scope in attributeScopes" ng-value="scope"> 23 <md-option ng-repeat="scope in attributeScopes" ng-value="scope">
24 {{scope.name | translate}} 24 {{scope.name | translate}}
25 </md-option> 25 </md-option>
@@ -38,7 +38,7 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter @@ -38,7 +38,7 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter
38 if (scope.excludeEntityIds && scope.excludeEntityIds.length) { 38 if (scope.excludeEntityIds && scope.excludeEntityIds.length) {
39 limit += scope.excludeEntityIds.length; 39 limit += scope.excludeEntityIds.length;
40 } 40 }
41 - entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit, null, scope.entitySubtype).then(function success(result) { 41 + entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit, {ignoreLoading: true}, scope.entitySubtype).then(function success(result) {
42 if (result) { 42 if (result) {
43 if (scope.excludeEntityIds && scope.excludeEntityIds.length) { 43 if (scope.excludeEntityIds && scope.excludeEntityIds.length) {
44 var entities = []; 44 var entities = [];
@@ -38,7 +38,7 @@ export default function EntityListDirective($compile, $templateCache, $q, $mdUti @@ -38,7 +38,7 @@ export default function EntityListDirective($compile, $templateCache, $q, $mdUti
38 38
39 scope.fetchEntities = function(searchText, limit) { 39 scope.fetchEntities = function(searchText, limit) {
40 var deferred = $q.defer(); 40 var deferred = $q.defer();
41 - entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then( 41 + entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit, {ignoreLoading: true}).then(
42 function success(result) { 42 function success(result) {
43 if (result) { 43 if (result) {
44 deferred.resolve(result); 44 deferred.resolve(result);
@@ -93,9 +93,9 @@ export default function EntitySubtypeAutocomplete($compile, $templateCache, $q, @@ -93,9 +93,9 @@ export default function EntitySubtypeAutocomplete($compile, $templateCache, $q,
93 if (!scope.entitySubtypes) { 93 if (!scope.entitySubtypes) {
94 var entitySubtypesPromise; 94 var entitySubtypesPromise;
95 if (scope.entityType == types.entityType.asset) { 95 if (scope.entityType == types.entityType.asset) {
96 - entitySubtypesPromise = assetService.getAssetTypes(); 96 + entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true});
97 } else if (scope.entityType == types.entityType.device) { 97 } else if (scope.entityType == types.entityType.device) {
98 - entitySubtypesPromise = deviceService.getDeviceTypes(); 98 + entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true});
99 } 99 }
100 if (entitySubtypesPromise) { 100 if (entitySubtypesPromise) {
101 entitySubtypesPromise.then( 101 entitySubtypesPromise.then(
@@ -95,9 +95,9 @@ export default function EntitySubtypeListDirective($compile, $templateCache, $q, @@ -95,9 +95,9 @@ export default function EntitySubtypeListDirective($compile, $templateCache, $q,
95 if (!scope.entitySubtypes) { 95 if (!scope.entitySubtypes) {
96 var entitySubtypesPromise; 96 var entitySubtypesPromise;
97 if (scope.entityType == types.entityType.asset) { 97 if (scope.entityType == types.entityType.asset) {
98 - entitySubtypesPromise = assetService.getAssetTypes(); 98 + entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true});
99 } else if (scope.entityType == types.entityType.device) { 99 } else if (scope.entityType == types.entityType.device) {
100 - entitySubtypesPromise = deviceService.getDeviceTypes(); 100 + entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true});
101 } 101 }
102 if (entitySubtypesPromise) { 102 if (entitySubtypesPromise) {
103 entitySubtypesPromise.then( 103 entitySubtypesPromise.then(
@@ -73,9 +73,9 @@ export default function EntitySubtypeSelect($compile, $templateCache, $translate @@ -73,9 +73,9 @@ export default function EntitySubtypeSelect($compile, $templateCache, $translate
73 scope.entitySubtypes = []; 73 scope.entitySubtypes = [];
74 var entitySubtypesPromise; 74 var entitySubtypesPromise;
75 if (scope.entityType == types.entityType.asset) { 75 if (scope.entityType == types.entityType.asset) {
76 - entitySubtypesPromise = assetService.getAssetTypes(); 76 + entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true});
77 } else if (scope.entityType == types.entityType.device) { 77 } else if (scope.entityType == types.entityType.device) {
78 - entitySubtypesPromise = deviceService.getDeviceTypes(); 78 + entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true});
79 } 79 }
80 if (entitySubtypesPromise) { 80 if (entitySubtypesPromise) {
81 entitySubtypesPromise.then( 81 entitySubtypesPromise.then(
@@ -26,16 +26,16 @@ @@ -26,16 +26,16 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 <md-content class="md-padding" layout="column"> 33 <md-content class="md-padding" layout="column">
34 - <fieldset ng-disabled="loading"> 34 + <fieldset ng-disabled="$root.loading">
35 <tb-relation-type-autocomplete ng-disabled="!vm.isAdd" 35 <tb-relation-type-autocomplete ng-disabled="!vm.isAdd"
36 ng-model="vm.relation.type" 36 ng-model="vm.relation.type"
37 tb-required="true" 37 tb-required="true"
38 - ng-disabled="loading"> 38 + ng-disabled="$root.loading">
39 </tb-relation-type-autocomplete> 39 </tb-relation-type-autocomplete>
40 <small>{{(vm.direction == vm.types.entitySearchDirection.from ? 40 <small>{{(vm.direction == vm.types.entitySearchDirection.from ?
41 'relation.to-entity' : 'relation.from-entity') | translate}}</small> 41 'relation.to-entity' : 'relation.from-entity') | translate}}</small>
@@ -61,11 +61,11 @@ @@ -61,11 +61,11 @@
61 </md-dialog-content> 61 </md-dialog-content>
62 <md-dialog-actions layout="row"> 62 <md-dialog-actions layout="row">
63 <span flex></span> 63 <span flex></span>
64 - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" 64 + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit"
65 class="md-raised md-primary"> 65 class="md-raised md-primary">
66 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} 66 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }}
67 </md-button> 67 </md-button>
68 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | 68 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
69 translate }} 69 translate }}
70 </md-button> 70 </md-button>
71 </md-dialog-actions> 71 </md-dialog-actions>
@@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
37 allowed-entity-types="allowedEntityTypes" 37 allowed-entity-types="allowedEntityTypes"
38 tb-required="false"> 38 tb-required="false">
39 </tb-entity-type-list> 39 </tb-entity-type-list>
40 - <md-button ng-disabled="loading" class="md-icon-button md-primary" style="width: 40px; min-width: 40px;" 40 + <md-button ng-disabled="$root.loading" class="md-icon-button md-primary" style="width: 40px; min-width: 40px;"
41 ng-click="removeFilter($event, filter)" aria-label="{{ 'action.remove' | translate }}"> 41 ng-click="removeFilter($event, filter)" aria-label="{{ 'action.remove' | translate }}">
42 <md-tooltip md-direction="top"> 42 <md-tooltip md-direction="top">
43 {{ 'relation.remove-relation-filter' | translate }} 43 {{ 'relation.remove-relation-filter' | translate }}
@@ -54,7 +54,7 @@ @@ -54,7 +54,7 @@
54 class="tb-prompt" translate>relation.any-relation</span> 54 class="tb-prompt" translate>relation.any-relation</span>
55 </div> 55 </div>
56 <div> 56 <div>
57 - <md-button ng-disabled="loading" class="md-primary md-raised" ng-click="addFilter($event)" aria-label="{{ 'action.add' | translate }}"> 57 + <md-button ng-disabled="$root.loading" class="md-primary md-raised" ng-click="addFilter($event)" aria-label="{{ 'action.add' | translate }}">
58 <md-tooltip md-direction="top"> 58 <md-tooltip md-direction="top">
59 {{ 'relation.add-relation-filter' | translate }} 59 {{ 'relation.add-relation-filter' | translate }}
60 </md-tooltip> 60 </md-tooltip>
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 <section layout="row"> 19 <section layout="row">
20 <md-input-container class="md-block" style="width: 200px;"> 20 <md-input-container class="md-block" style="width: 200px;">
21 <label translate>relation.direction</label> 21 <label translate>relation.direction</label>
22 - <md-select ng-model="vm.direction" ng-disabled="loading"> 22 + <md-select ng-model="vm.direction" ng-disabled="$root.loading">
23 <md-option ng-repeat="direction in vm.types.entitySearchDirection" ng-value="direction"> 23 <md-option ng-repeat="direction in vm.types.entitySearchDirection" ng-value="direction">
24 {{ ('relation.search-direction.' + direction) | translate}} 24 {{ ('relation.search-direction.' + direction) | translate}}
25 </md-option> 25 </md-option>
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 </md-dialog-content> 35 </md-dialog-content>
36 <md-dialog-actions layout="row"> 36 <md-dialog-actions layout="row">
37 <span flex></span> 37 <span flex></span>
38 - <md-button ng-disabled="loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' | 38 + <md-button ng-disabled="$root.loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' |
39 translate }} 39 translate }}
40 </md-button> 40 </md-button>
41 </md-dialog-actions> 41 </md-dialog-actions>
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 <section layout="row"> 19 <section layout="row">
20 <md-input-container class="md-block" style="width: 200px;"> 20 <md-input-container class="md-block" style="width: 200px;">
21 <label translate>event.event-type</label> 21 <label translate>event.event-type</label>
22 - <md-select ng-model="eventType" ng-disabled="loading()"> 22 + <md-select ng-model="eventType" ng-disabled="$root.loading">
23 <md-option ng-repeat="type in eventTypes" ng-value="type.value"> 23 <md-option ng-repeat="type in eventTypes" ng-value="type.value">
24 {{type.name | translate}} 24 {{type.name | translate}}
25 </md-option> 25 </md-option>
@@ -30,8 +30,8 @@ @@ -30,8 +30,8 @@
30 <md-list flex layout="column" class="md-whiteframe-z1 tb-event-table"> 30 <md-list flex layout="column" class="md-whiteframe-z1 tb-event-table">
31 <md-list class="tb-row tb-header" layout="row" tb-event-header event-type="{{eventType}}"> 31 <md-list class="tb-row tb-header" layout="row" tb-event-header event-type="{{eventType}}">
32 </md-list> 32 </md-list>
33 - <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!loading()"  
34 - ng-show="loading()"></md-progress-linear> 33 + <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!$root.loading"
  34 + ng-show="$root.loading"></md-progress-linear>
35 <md-divider></md-divider> 35 <md-divider></md-divider>
36 <span translate layout-align="center center" 36 <span translate layout-align="center center"
37 style="margin-top: 25px;" 37 style="margin-top: 25px;"
@@ -27,14 +27,14 @@ @@ -27,14 +27,14 @@
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 29
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> 30 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
31 31
32 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 32 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
33 33
34 <md-dialog-content> 34 <md-dialog-content>
35 <div class="md-dialog-content"> 35 <div class="md-dialog-content">
36 <md-content class="md-padding" layout="column"> 36 <md-content class="md-padding" layout="column">
37 - <fieldset ng-disabled="loading"> 37 + <fieldset ng-disabled="$root.loading">
38 <section flex layout="row"> 38 <section flex layout="row">
39 <md-input-container flex="60" class="md-block" md-is-error="theForm.extensionId.$touched && theForm.extensionId.$invalid"> 39 <md-input-container flex="60" class="md-block" md-is-error="theForm.extensionId.$touched && theForm.extensionId.$invalid">
40 <label translate>extension.extension-id</label> 40 <label translate>extension.extension-id</label>
@@ -74,7 +74,7 @@ @@ -74,7 +74,7 @@
74 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} 74 {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }}
75 </md-button> 75 </md-button>
76 76
77 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }} 77 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}
78 </md-button> 78 </md-button>
79 </md-dialog-actions> 79 </md-dialog-actions>
80 </form> 80 </form>
@@ -26,11 +26,11 @@ @@ -26,11 +26,11 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
  30 + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 31 <md-dialog-content>
32 <div class="md-dialog-content"> 32 <div class="md-dialog-content">
33 - <fieldset ng-disabled="loading"> 33 + <fieldset ng-disabled="$root.loading">
34 <div layout="column" layout-padding> 34 <div layout="column" layout-padding>
35 <div class="tb-container"> 35 <div class="tb-container">
36 <label class="tb-label" translate>{{ vm.importFileLabel }}</label> 36 <label class="tb-label" translate>{{ vm.importFileLabel }}</label>
@@ -63,10 +63,10 @@ @@ -63,10 +63,10 @@
63 </md-dialog-content> 63 </md-dialog-content>
64 <md-dialog-actions layout="row"> 64 <md-dialog-actions layout="row">
65 <span flex></span> 65 <span flex></span>
66 - <md-button ng-disabled="loading || !theForm.$dirty || !theForm.$valid || !vm.importData" type="submit" class="md-raised md-primary"> 66 + <md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid || !vm.importData" type="submit" class="md-raised md-primary">
67 {{ 'action.import' | translate }} 67 {{ 'action.import' | translate }}
68 </md-button> 68 </md-button>
69 - <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 69 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
70 </md-dialog-actions> 70 </md-dialog-actions>
71 </form> 71 </form>
72 </md-dialog> 72 </md-dialog>
@@ -76,7 +76,7 @@ @@ -76,7 +76,7 @@
76 </tb-user-menu> 76 </tb-user-menu>
77 </div> 77 </div>
78 </md-toolbar> 78 </md-toolbar>
79 - <md-progress-linear class="md-warn" style="z-index: 10; max-height: 0px; width: 100%;" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> 79 + <md-progress-linear class="md-warn" style="z-index: 10; max-height: 0px; width: 100%;" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
80 80
81 <div flex layout="column" id="toast-parent" style="position: relative;"> 81 <div flex layout="column" id="toast-parent" style="position: relative;">
82 <md-content ng-cloak flex layout="column" class="page-content" ui-view name="content"></md-content> 82 <md-content ng-cloak flex layout="column" class="page-content" ui-view name="content"></md-content>
@@ -1213,6 +1213,7 @@ export default angular.module('thingsboard.locale', []) @@ -1213,6 +1213,7 @@ export default angular.module('thingsboard.locale', [])
1213 "remove-widget-title": "Are you sure you want to remove the widget '{{widgetTitle}}'?", 1213 "remove-widget-title": "Are you sure you want to remove the widget '{{widgetTitle}}'?",
1214 "remove-widget-text": "After the confirmation the widget and all related data will become unrecoverable.", 1214 "remove-widget-text": "After the confirmation the widget and all related data will become unrecoverable.",
1215 "timeseries": "Time series", 1215 "timeseries": "Time series",
  1216 + "search-data": "Search data",
1216 "latest-values": "Latest values", 1217 "latest-values": "Latest values",
1217 "rpc": "Control widget", 1218 "rpc": "Control widget",
1218 "alarm": "Alarm widget", 1219 "alarm": "Alarm widget",
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 </md-card-title-text> 23 </md-card-title-text>
24 </md-card-title> 24 </md-card-title>
25 <md-progress-linear class="md-warn" style="z-index: 1; max-height: 5px; width: inherit; position: absolute" 25 <md-progress-linear class="md-warn" style="z-index: 1; max-height: 5px; width: inherit; position: absolute"
26 - md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> 26 + md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
27 <md-card-content> 27 <md-card-content>
28 <form class="create-password-form" ng-submit="vm.createPassword()"> 28 <form class="create-password-form" ng-submit="vm.createPassword()">
29 <div layout="column" layout-padding="" id="toast-parent"> 29 <div layout="column" layout-padding="" id="toast-parent">
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 </md-card-title-text> 23 </md-card-title-text>
24 </md-card-title> 24 </md-card-title>
25 <md-progress-linear class="md-warn" style="z-index: 1; max-height: 5px; width: inherit; position: absolute" 25 <md-progress-linear class="md-warn" style="z-index: 1; max-height: 5px; width: inherit; position: absolute"
26 - md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> 26 + md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
27 <md-card-content> 27 <md-card-content>
28 <form class="login-form" ng-submit="vm.login()"> 28 <form class="login-form" ng-submit="vm.login()">
29 <div layout="column" layout-padding="" id="toast-parent"> 29 <div layout="column" layout-padding="" id="toast-parent">
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 </md-card-title-text> 23 </md-card-title-text>
24 </md-card-title> 24 </md-card-title>
25 <md-progress-linear class="md-warn" style="z-index: 1; max-height: 5px; width: inherit; position: absolute" 25 <md-progress-linear class="md-warn" style="z-index: 1; max-height: 5px; width: inherit; position: absolute"
26 - md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> 26 + md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>
27 <md-card-content> 27 <md-card-content>
28 <form class="request-password-reset-form" ng-submit="vm.sendResetPasswordLink()"> 28 <form class="request-password-reset-form" ng-submit="vm.sendResetPasswordLink()">
29 <div layout="column" layout-padding="" id="toast-parent"> 29 <div layout="column" layout-padding="" id="toast-parent">