Commit 69422fea0e98e1722ee25c1b6503b305c9b7341b
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 | 126 | <artifactId>jjwt</artifactId> |
127 | 127 | </dependency> |
128 | 128 | <dependency> |
129 | - <groupId>joda-time</groupId> | |
130 | - <artifactId>joda-time</artifactId> | |
131 | - </dependency> | |
132 | - <dependency> | |
133 | 129 | <groupId>org.apache.velocity</groupId> |
134 | 130 | <artifactId>velocity</artifactId> |
135 | 131 | </dependency> | ... | ... |
... | ... | @@ -112,9 +112,9 @@ |
112 | 112 | "templateHtml": "<tb-timeseries-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-timeseries-table-widget>", |
113 | 113 | "templateCss": "", |
114 | 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 | 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 | 62 | private static final Executor executor = Executors.newSingleThreadExecutor(); |
63 | 63 | public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!"; |
64 | 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 | 67 | private final SharedPluginProcessingContext pluginCtx; |
67 | 68 | private final Optional<PluginApiCallSecurityContext> securityCtx; |
... | ... | @@ -309,7 +310,7 @@ public final class PluginProcessingContext implements PluginContext { |
309 | 310 | ListenableFuture<Device> deviceFuture = pluginCtx.deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId())); |
310 | 311 | Futures.addCallback(deviceFuture, getCallback(callback, device -> { |
311 | 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 | 314 | } else { |
314 | 315 | if (!device.getTenantId().equals(ctx.getTenantId())) { |
315 | 316 | return ValidationResult.accessDenied("Device doesn't belong to the current Tenant!"); | ... | ... |
... | ... | @@ -47,8 +47,8 @@ public class WebSocketConfiguration implements WebSocketConfigurer { |
47 | 47 | @Bean |
48 | 48 | public ServletServerContainerFactoryBean createWebSocketContainer() { |
49 | 49 | ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); |
50 | - container.setMaxTextMessageBufferSize(8192); | |
51 | - container.setMaxBinaryMessageBufferSize(8192); | |
50 | + container.setMaxTextMessageBufferSize(32768); | |
51 | + container.setMaxBinaryMessageBufferSize(32768); | |
52 | 52 | return container; |
53 | 53 | } |
54 | 54 | ... | ... |
... | ... | @@ -82,7 +82,7 @@ public class CustomerController extends BaseController { |
82 | 82 | |
83 | 83 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
84 | 84 | @RequestMapping(value = "/customer", method = RequestMethod.POST) |
85 | - @ResponseBody | |
85 | + @ResponseBody | |
86 | 86 | public Customer saveCustomer(@RequestBody Customer customer) throws ThingsboardException { |
87 | 87 | try { |
88 | 88 | customer.setTenantId(getCurrentUser().getTenantId()); |
... | ... | @@ -107,7 +107,7 @@ public class CustomerController extends BaseController { |
107 | 107 | } |
108 | 108 | |
109 | 109 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
110 | - @RequestMapping(value = "/customers", params = { "limit" }, method = RequestMethod.GET) | |
110 | + @RequestMapping(value = "/customers", params = {"limit"}, method = RequestMethod.GET) | |
111 | 111 | @ResponseBody |
112 | 112 | public TextPageData<Customer> getCustomers(@RequestParam int limit, |
113 | 113 | @RequestParam(required = false) String textSearch, |
... | ... | @@ -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 | 77 | log.warn("[{}] Failed to find session", session.getId()); |
78 | 78 | session.close(CloseStatus.SERVER_ERROR.withReason("Session not found!")); |
79 | 79 | } |
80 | - session.sendMessage(message); | |
81 | 80 | } catch (IOException e) { |
82 | 81 | log.warn("IO error", e); |
83 | 82 | } | ... | ... |
... | ... | @@ -96,7 +96,7 @@ public class DefaultMailService implements MailService { |
96 | 96 | javaMailProperties.put(MAIL_PROP + protocol + ".port", jsonConfig.get("smtpPort").asText()); |
97 | 97 | javaMailProperties.put(MAIL_PROP + protocol + ".timeout", jsonConfig.get("timeout").asText()); |
98 | 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 | 100 | return javaMailProperties; |
101 | 101 | } |
102 | 102 | ... | ... |
... | ... | @@ -20,7 +20,6 @@ import io.jsonwebtoken.Jws; |
20 | 20 | import io.jsonwebtoken.Jwts; |
21 | 21 | import io.jsonwebtoken.SignatureAlgorithm; |
22 | 22 | import org.apache.commons.lang3.StringUtils; |
23 | -import org.joda.time.DateTime; | |
24 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 24 | import org.springframework.stereotype.Component; |
26 | 25 | import org.thingsboard.server.common.data.id.CustomerId; |
... | ... | @@ -31,7 +30,9 @@ import org.thingsboard.server.config.JwtSettings; |
31 | 30 | import org.thingsboard.server.service.security.model.SecurityUser; |
32 | 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 | 36 | import java.util.List; |
36 | 37 | import java.util.UUID; |
37 | 38 | import java.util.stream.Collectors; |
... | ... | @@ -81,13 +82,13 @@ public class JwtTokenFactory { |
81 | 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 | 87 | String token = Jwts.builder() |
87 | 88 | .setClaims(claims) |
88 | 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 | 92 | .signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) |
92 | 93 | .compact(); |
93 | 94 | |
... | ... | @@ -129,11 +130,11 @@ public class JwtTokenFactory { |
129 | 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 | 135 | UserPrincipal principal = securityUser.getUserPrincipal(); |
135 | 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 | 138 | claims.put(USER_ID, securityUser.getId().getId().toString()); |
138 | 139 | claims.put(IS_PUBLIC, principal.getType() == UserPrincipal.Type.PUBLIC_ID); |
139 | 140 | |
... | ... | @@ -141,8 +142,8 @@ public class JwtTokenFactory { |
141 | 142 | .setClaims(claims) |
142 | 143 | .setIssuer(settings.getTokenIssuer()) |
143 | 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 | 147 | .signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) |
147 | 148 | .compact(); |
148 | 149 | ... | ... |
... | ... | @@ -107,6 +107,11 @@ public abstract class AbstractControllerTest { |
107 | 107 | protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org"; |
108 | 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 | 115 | protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), |
111 | 116 | MediaType.APPLICATION_JSON.getSubtype(), |
112 | 117 | Charset.forName("utf8")); |
... | ... | @@ -366,7 +371,7 @@ public abstract class AbstractControllerTest { |
366 | 371 | } |
367 | 372 | |
368 | 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 | 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 | 379 | } |
375 | 380 | |
376 | 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 | 389 | protected <T> T doDelete(String urlTemplate, Class<T> responseClass, String... params) throws Exception { |
... | ... | @@ -396,12 +405,13 @@ public abstract class AbstractControllerTest { |
396 | 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 | 409 | MockHttpServletRequestBuilder postRequest = post(urlTemplate); |
401 | 410 | setJwtToken(postRequest); |
402 | 411 | String json = json(content); |
403 | 412 | postRequest.contentType(contentType).content(json); |
404 | 413 | MvcResult result = mockMvc.perform(postRequest).andReturn(); |
414 | + result.getAsyncResult(timeout); | |
405 | 415 | return mockMvc.perform(asyncDispatch(result)); |
406 | 416 | } |
407 | 417 | |
... | ... | @@ -414,8 +424,8 @@ public abstract class AbstractControllerTest { |
414 | 424 | |
415 | 425 | protected void populateParams(MockHttpServletRequestBuilder request, String... params) { |
416 | 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 | 429 | for (int i = 0; i < params.length; i += 2) { |
420 | 430 | paramsMap.add(params[i], params[i + 1]); |
421 | 431 | } | ... | ... |
... | ... | @@ -15,21 +15,23 @@ |
15 | 15 | */ |
16 | 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 | 22 | import lombok.extern.slf4j.Slf4j; |
19 | 23 | import org.apache.commons.lang3.StringUtils; |
20 | 24 | import org.eclipse.paho.client.mqttv3.*; |
21 | 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 | 27 | import org.thingsboard.server.common.data.Device; |
25 | 28 | import org.thingsboard.server.common.data.Tenant; |
26 | 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 | 32 | import org.thingsboard.server.common.data.security.Authority; |
28 | 33 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
29 | 34 | import org.thingsboard.server.controller.AbstractControllerTest; |
30 | -import org.thingsboard.server.dao.service.DaoNoSqlTest; | |
31 | - | |
32 | -import java.util.UUID; | |
33 | 35 | |
34 | 36 | import static org.junit.Assert.assertEquals; |
35 | 37 | import static org.junit.Assert.assertNotNull; |
... | ... | @@ -42,15 +44,19 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. |
42 | 44 | public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractControllerTest { |
43 | 45 | |
44 | 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 | 49 | private Tenant savedTenant; |
48 | 50 | private User tenantAdmin; |
51 | + private Long asyncContextTimeoutToUseRpcPlugin; | |
52 | + | |
49 | 53 | |
50 | 54 | @Before |
51 | 55 | public void beforeTest() throws Exception { |
52 | 56 | loginSysAdmin(); |
53 | 57 | |
58 | + asyncContextTimeoutToUseRpcPlugin = getAsyncContextTimeoutToUseRpcPlugin(); | |
59 | + | |
54 | 60 | Tenant tenant = new Tenant(); |
55 | 61 | tenant.setTitle("My tenant"); |
56 | 62 | savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
... | ... | @@ -70,8 +76,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
70 | 76 | public void afterTest() throws Exception { |
71 | 77 | loginSysAdmin(); |
72 | 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 | 107 | } |
103 | 108 | |
104 | 109 | @Test |
105 | - @Ignore // TODO: figure out the right error code for this case. Ignored due to failure: expected 408 but was: 200 | |
106 | 110 | public void testServerMqttOneWayRpcDeviceOffline() throws Exception { |
107 | 111 | Device device = new Device(); |
108 | 112 | device.setName("Test One-Way Server-Side RPC Device Offline"); |
... | ... | @@ -115,29 +119,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
115 | 119 | |
116 | 120 | String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; |
117 | 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 | 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 | 128 | public void testServerMqttOneWayRpcDeviceDoesNotExist() throws Exception { |
131 | 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 | 137 | @Test |
... | ... | @@ -168,7 +162,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
168 | 162 | } |
169 | 163 | |
170 | 164 | @Test |
171 | - @Ignore // TODO: figure out the right error code for this case. Ignored due to failure: expected 408 but was: 200 | |
172 | 165 | public void testServerMqttTwoWayRpcDeviceOffline() throws Exception { |
173 | 166 | Device device = new Device(); |
174 | 167 | device.setName("Test Two-Way Server-Side RPC Device Offline"); |
... | ... | @@ -181,29 +174,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
181 | 174 | |
182 | 175 | String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; |
183 | 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 | 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 | 183 | public void testServerMqttTwoWayRpcDeviceDoesNotExist() throws Exception { |
197 | 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 | 192 | private Device getSavedDevice(Device device) throws Exception { |
... | ... | @@ -214,6 +197,13 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
214 | 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 | 207 | private static class TestMqttCallback implements MqttCallback { |
218 | 208 | |
219 | 209 | private final MqttAsyncClient client; |
... | ... | @@ -228,10 +218,10 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
228 | 218 | |
229 | 219 | @Override |
230 | 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 | 222 | MqttMessage message = new MqttMessage(); |
233 | 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 | 225 | client.publish(responseTopic, message); |
236 | 226 | } |
237 | 227 | ... | ... |
... | ... | @@ -22,20 +22,24 @@ import org.thingsboard.server.common.data.id.TenantId; |
22 | 22 | import org.thingsboard.server.common.data.page.TextPageData; |
23 | 23 | import org.thingsboard.server.common.data.page.TextPageLink; |
24 | 24 | |
25 | +import java.util.Optional; | |
26 | + | |
25 | 27 | public interface CustomerService { |
26 | 28 | |
27 | 29 | Customer findCustomerById(CustomerId customerId); |
28 | 30 | |
31 | + Optional<Customer> findCustomerByTenantIdAndTitle(TenantId tenantId, String title); | |
32 | + | |
29 | 33 | ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId); |
30 | 34 | |
31 | 35 | Customer saveCustomer(Customer customer); |
32 | - | |
36 | + | |
33 | 37 | void deleteCustomer(CustomerId customerId); |
34 | 38 | |
35 | 39 | Customer findOrCreatePublicCustomer(TenantId tenantId); |
36 | 40 | |
37 | 41 | TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink); |
38 | - | |
42 | + | |
39 | 43 | void deleteCustomersByTenantId(TenantId tenantId); |
40 | 44 | |
41 | 45 | } | ... | ... |
... | ... | @@ -52,6 +52,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom |
52 | 52 | |
53 | 53 | private static final String PUBLIC_CUSTOMER_TITLE = "Public"; |
54 | 54 | public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; |
55 | + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; | |
55 | 56 | |
56 | 57 | @Autowired |
57 | 58 | private CustomerDao customerDao; |
... | ... | @@ -79,6 +80,13 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom |
79 | 80 | } |
80 | 81 | |
81 | 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 | 90 | public ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId) { |
83 | 91 | log.trace("Executing findCustomerByIdAsync [{}]", customerId); |
84 | 92 | validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); | ... | ... |
... | ... | @@ -33,8 +33,7 @@ |
33 | 33 | <spring.version>4.3.4.RELEASE</spring.version> |
34 | 34 | <spring-security.version>4.2.0.RELEASE</spring-security.version> |
35 | 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 | 37 | <junit.version>4.12</junit.version> |
39 | 38 | <slf4j.version>1.7.7</slf4j.version> |
40 | 39 | <logback.version>1.2.3</logback.version> |
... | ... | @@ -484,11 +483,6 @@ |
484 | 483 | <version>${jjwt.version}</version> |
485 | 484 | </dependency> |
486 | 485 | <dependency> |
487 | - <groupId>joda-time</groupId> | |
488 | - <artifactId>joda-time</artifactId> | |
489 | - <version>${joda-time.version}</version> | |
490 | - </dependency> | |
491 | - <dependency> | |
492 | 486 | <groupId>org.apache.velocity</groupId> |
493 | 487 | <artifactId>velocity</artifactId> |
494 | 488 | <version>${velocity.version}</version> | ... | ... |
... | ... | @@ -29,13 +29,12 @@ import org.springframework.web.client.RestTemplate; |
29 | 29 | import org.thingsboard.server.common.data.Customer; |
30 | 30 | import org.thingsboard.server.common.data.Device; |
31 | 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 | 32 | import org.thingsboard.server.common.data.asset.Asset; |
35 | 33 | import org.thingsboard.server.common.data.id.AssetId; |
36 | 34 | import org.thingsboard.server.common.data.id.CustomerId; |
37 | 35 | import org.thingsboard.server.common.data.id.DeviceId; |
38 | 36 | import org.thingsboard.server.common.data.id.EntityId; |
37 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
39 | 38 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
40 | 39 | |
41 | 40 | import java.io.IOException; |
... | ... | @@ -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 | 110 | public Customer createCustomer(String title) { |
82 | 111 | Customer customer = new Customer(); |
83 | 112 | customer.setTitle(title); |
... | ... | @@ -112,6 +141,14 @@ public class RestClient implements ClientHttpRequestInterceptor { |
112 | 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 | 152 | public DeviceCredentials getCredentials(DeviceId id) { |
116 | 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 | 74 | |
75 | 75 | keytool -genkeypair -v \ |
76 | 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 | 77 | -keystore $CLIENT_FILE_PREFIX.jks \ |
79 | 78 | -keypass $CLIENT_KEY_PASSWORD \ |
80 | 79 | -storepass $CLIENT_KEYSTORE_PASSWORD \ |
81 | 80 | -keyalg RSA \ |
82 | 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 | 85 | echo "Converting keystore to pkcs12" |
86 | 86 | keytool -importkeystore \ | ... | ... |
... | ... | @@ -22,11 +22,11 @@ |
22 | 22 | <span translate class="md-headline">admin.general-settings</span> |
23 | 23 | </md-card-title-text> |
24 | 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 | 27 | <md-card-content> |
28 | 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 | 30 | <md-input-container class="md-block"> |
31 | 31 | <label translate>admin.base-url</label> |
32 | 32 | <input required name="baseUrl" ng-model="vm.settings.jsonValue.baseUrl"> |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | </div> |
36 | 36 | </md-input-container> |
37 | 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 | 39 | </div> |
40 | 40 | </fieldset> |
41 | 41 | </form> | ... | ... |
... | ... | @@ -24,11 +24,11 @@ |
24 | 24 | <div id="help-container"></div> |
25 | 25 | </md-card-title-text> |
26 | 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 | 29 | <md-card-content> |
30 | 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 | 32 | <md-input-container class="md-block"> |
33 | 33 | <label translate>admin.mail-from</label> |
34 | 34 | <input required name="mailFrom" ng-model="vm.settings.jsonValue.mailFrom"> |
... | ... | @@ -38,7 +38,7 @@ |
38 | 38 | </md-input-container> |
39 | 39 | <md-input-container class="md-block"> |
40 | 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 | 42 | <md-option ng-repeat="smtpProtocol in vm.smtpProtocols" value="{{smtpProtocol}}"> |
43 | 43 | {{smtpProtocol.toUpperCase()}} |
44 | 44 | </md-option> |
... | ... | @@ -78,7 +78,7 @@ |
78 | 78 | <div translate ng-message="md-maxlength">admin.timeout-invalid</div> |
79 | 79 | </div> |
80 | 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 | 82 | aria-label="{{ 'admin.enable-tls' | translate }}" ng-model="vm.settings.jsonValue.enableTls">{{ 'admin.enable-tls' | translate }}</md-checkbox> |
83 | 83 | <md-input-container class="md-block"> |
84 | 84 | <label translate>common.username</label> |
... | ... | @@ -89,8 +89,8 @@ |
89 | 89 | <input name="password" placeholder="{{ 'common.enter-password' | translate }}" type="password" ng-model="vm.settings.jsonValue.password"> |
90 | 90 | </md-input-container> |
91 | 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 | 94 | </div> |
95 | 95 | </fieldset> |
96 | 96 | </form> | ... | ... |
... | ... | @@ -87,7 +87,7 @@ |
87 | 87 | <md-button ng-if="vm.allowAcknowledgment && (vm.alarm.status==vm.types.alarmStatus.activeUnack || |
88 | 88 | vm.alarm.status==vm.types.alarmStatus.clearedUnack)" |
89 | 89 | class="md-raised md-primary" |
90 | - ng-disabled="loading" | |
90 | + ng-disabled="$root.loading" | |
91 | 91 | ng-click="vm.acknowledge()" |
92 | 92 | style="margin-right:20px;">{{ 'alarm.acknowledge' | |
93 | 93 | translate }} |
... | ... | @@ -95,12 +95,12 @@ |
95 | 95 | <md-button ng-if="vm.allowClear && (vm.alarm.status==vm.types.alarmStatus.activeAck || |
96 | 96 | vm.alarm.status==vm.types.alarmStatus.activeUnack)" |
97 | 97 | class="md-raised md-primary" |
98 | - ng-disabled="loading" | |
98 | + ng-disabled="$root.loading" | |
99 | 99 | ng-click="vm.clear()">{{ 'alarm.clear' | |
100 | 100 | translate }} |
101 | 101 | </md-button> |
102 | 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 | 104 | translate }} |
105 | 105 | </md-button> |
106 | 106 | </md-dialog-actions> | ... | ... |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | <section layout="row"> |
20 | 20 | <md-input-container class="md-block" style="width: 200px;"> |
21 | 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 | 23 | <md-option ng-repeat="searchStatus in types.alarmSearchStatus" ng-value="searchStatus"> |
24 | 24 | {{ ('alarm.search-status.' + searchStatus) | translate }} |
25 | 25 | </md-option> |
... | ... | @@ -31,8 +31,8 @@ |
31 | 31 | <md-list flex layout="column" class="tb-alarm-table"> |
32 | 32 | <md-list class="tb-row tb-header" layout="row" tb-alarm-header> |
33 | 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 | 36 | <md-divider></md-divider> |
37 | 37 | <span translate layout-align="center center" |
38 | 38 | style="margin-top: 25px;" | ... | ... |
... | ... | @@ -265,10 +265,10 @@ function AssetService($http, $q, customerService, userService) { |
265 | 265 | return deferred.promise; |
266 | 266 | } |
267 | 267 | |
268 | - function getAssetTypes() { | |
268 | + function getAssetTypes(config) { | |
269 | 269 | var deferred = $q.defer(); |
270 | 270 | var url = '/api/asset/types'; |
271 | - $http.get(url).then(function success(response) { | |
271 | + $http.get(url, config).then(function success(response) { | |
272 | 272 | deferred.resolve(response.data); |
273 | 273 | }, function fail() { |
274 | 274 | deferred.reject(); | ... | ... |
... | ... | @@ -35,7 +35,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
35 | 35 | |
36 | 36 | return service; |
37 | 37 | |
38 | - function getEntityKeys(entityType, entityId, query, type) { | |
38 | + function getEntityKeys(entityType, entityId, query, type, config) { | |
39 | 39 | var deferred = $q.defer(); |
40 | 40 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; |
41 | 41 | if (type === types.dataKeyType.timeseries) { |
... | ... | @@ -43,7 +43,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
43 | 43 | } else if (type === types.dataKeyType.attribute) { |
44 | 44 | url += 'attributes'; |
45 | 45 | } |
46 | - $http.get(url, null).then(function success(response) { | |
46 | + $http.get(url, config).then(function success(response) { | |
47 | 47 | var result = []; |
48 | 48 | if (response.data) { |
49 | 49 | if (query) { | ... | ... |
... | ... | @@ -32,7 +32,7 @@ function CustomerService($http, $q, types) { |
32 | 32 | |
33 | 33 | return service; |
34 | 34 | |
35 | - function getCustomers(pageLink) { | |
35 | + function getCustomers(pageLink, config) { | |
36 | 36 | var deferred = $q.defer(); |
37 | 37 | var url = '/api/customers?limit=' + pageLink.limit; |
38 | 38 | if (angular.isDefined(pageLink.textSearch)) { |
... | ... | @@ -44,7 +44,7 @@ function CustomerService($http, $q, types) { |
44 | 44 | if (angular.isDefined(pageLink.textOffset)) { |
45 | 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 | 48 | deferred.resolve(response.data); |
49 | 49 | }, function fail() { |
50 | 50 | deferred.reject(); |
... | ... | @@ -52,10 +52,10 @@ function CustomerService($http, $q, types) { |
52 | 52 | return deferred.promise; |
53 | 53 | } |
54 | 54 | |
55 | - function getCustomer(customerId) { | |
55 | + function getCustomer(customerId, config) { | |
56 | 56 | var deferred = $q.defer(); |
57 | 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 | 59 | deferred.resolve(response.data); |
60 | 60 | }, function fail(response) { |
61 | 61 | deferred.reject(response.data); | ... | ... |
... | ... | @@ -43,7 +43,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { |
43 | 43 | |
44 | 44 | return service; |
45 | 45 | |
46 | - function getTenantDashboardsByTenantId(tenantId, pageLink) { | |
46 | + function getTenantDashboardsByTenantId(tenantId, pageLink, config) { | |
47 | 47 | var deferred = $q.defer(); |
48 | 48 | var url = '/api/tenant/' + tenantId + '/dashboards?limit=' + pageLink.limit; |
49 | 49 | if (angular.isDefined(pageLink.textSearch)) { |
... | ... | @@ -55,7 +55,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { |
55 | 55 | if (angular.isDefined(pageLink.textOffset)) { |
56 | 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 | 59 | deferred.resolve(response.data); |
60 | 60 | }, function fail() { |
61 | 61 | deferred.reject(); |
... | ... | @@ -63,7 +63,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { |
63 | 63 | return deferred.promise; |
64 | 64 | } |
65 | 65 | |
66 | - function getTenantDashboards(pageLink, applyCustomersInfo) { | |
66 | + function getTenantDashboards(pageLink, applyCustomersInfo, config) { | |
67 | 67 | var deferred = $q.defer(); |
68 | 68 | var url = '/api/tenant/dashboards?limit=' + pageLink.limit; |
69 | 69 | if (angular.isDefined(pageLink.textSearch)) { |
... | ... | @@ -75,7 +75,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { |
75 | 75 | if (angular.isDefined(pageLink.textOffset)) { |
76 | 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 | 79 | if (applyCustomersInfo) { |
80 | 80 | customerService.applyAssignedCustomersInfo(response.data.data).then( |
81 | 81 | function success(data) { |
... | ... | @@ -95,7 +95,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { |
95 | 95 | return deferred.promise; |
96 | 96 | } |
97 | 97 | |
98 | - function getCustomerDashboards(customerId, pageLink, applyCustomersInfo) { | |
98 | + function getCustomerDashboards(customerId, pageLink, applyCustomersInfo, config) { | |
99 | 99 | var deferred = $q.defer(); |
100 | 100 | var url = '/api/customer/' + customerId + '/dashboards?limit=' + pageLink.limit; |
101 | 101 | if (angular.isDefined(pageLink.textSearch)) { |
... | ... | @@ -107,7 +107,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { |
107 | 107 | if (angular.isDefined(pageLink.textOffset)) { |
108 | 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 | 111 | if (applyCustomersInfo) { |
112 | 112 | customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( |
113 | 113 | function success(data) { |
... | ... | @@ -158,10 +158,10 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { |
158 | 158 | return deferred.promise; |
159 | 159 | } |
160 | 160 | |
161 | - function getDashboardInfo(dashboardId) { | |
161 | + function getDashboardInfo(dashboardId, config) { | |
162 | 162 | var deferred = $q.defer(); |
163 | 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 | 165 | deferred.resolve(response.data); |
166 | 166 | }, function fail() { |
167 | 167 | deferred.reject(); | ... | ... |
... | ... | @@ -293,10 +293,10 @@ function DeviceService($http, $q, attributeService, customerService, types) { |
293 | 293 | return deferred.promise; |
294 | 294 | } |
295 | 295 | |
296 | - function getDeviceTypes() { | |
296 | + function getDeviceTypes(config) { | |
297 | 297 | var deferred = $q.defer(); |
298 | 298 | var url = '/api/device/types'; |
299 | - $http.get(url).then(function success(response) { | |
299 | + $http.get(url, config).then(function success(response) { | |
300 | 300 | deferred.resolve(response.data); |
301 | 301 | }, function fail() { |
302 | 302 | deferred.reject(); | ... | ... |
... | ... | @@ -175,10 +175,10 @@ function EntityRelationService($http, $q) { |
175 | 175 | return deferred.promise; |
176 | 176 | } |
177 | 177 | |
178 | - function findInfoByQuery(query) { | |
178 | + function findInfoByQuery(query, config) { | |
179 | 179 | var deferred = $q.defer(); |
180 | 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 | 182 | deferred.resolve(response.data); |
183 | 183 | }, function fail() { |
184 | 184 | deferred.reject(); | ... | ... |
... | ... | @@ -56,22 +56,22 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
56 | 56 | promise = assetService.getAsset(entityId, true, config); |
57 | 57 | break; |
58 | 58 | case types.entityType.tenant: |
59 | - promise = tenantService.getTenant(entityId); | |
59 | + promise = tenantService.getTenant(entityId, config); | |
60 | 60 | break; |
61 | 61 | case types.entityType.customer: |
62 | - promise = customerService.getCustomer(entityId); | |
62 | + promise = customerService.getCustomer(entityId, config); | |
63 | 63 | break; |
64 | 64 | case types.entityType.rule: |
65 | - promise = ruleService.getRule(entityId); | |
65 | + promise = ruleService.getRule(entityId, config); | |
66 | 66 | break; |
67 | 67 | case types.entityType.plugin: |
68 | - promise = pluginService.getPlugin(entityId); | |
68 | + promise = pluginService.getPlugin(entityId, config); | |
69 | 69 | break; |
70 | 70 | case types.entityType.dashboard: |
71 | - promise = dashboardService.getDashboardInfo(entityId); | |
71 | + promise = dashboardService.getDashboardInfo(entityId, config); | |
72 | 72 | break; |
73 | 73 | case types.entityType.user: |
74 | - promise = userService.getUser(entityId); | |
74 | + promise = userService.getUser(entityId, true, config); | |
75 | 75 | break; |
76 | 76 | case types.entityType.alarm: |
77 | 77 | $log.error('Get Alarm Entity is not implemented!'); |
... | ... | @@ -136,22 +136,28 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
136 | 136 | promise = assetService.getAssets(entityIds, config); |
137 | 137 | break; |
138 | 138 | case types.entityType.tenant: |
139 | - promise = getEntitiesByIdsPromise(tenantService.getTenant, entityIds); | |
139 | + promise = getEntitiesByIdsPromise( | |
140 | + (id) => tenantService.getTenant(id, config), entityIds); | |
140 | 141 | break; |
141 | 142 | case types.entityType.customer: |
142 | - promise = getEntitiesByIdsPromise(customerService.getCustomer, entityIds); | |
143 | + promise = getEntitiesByIdsPromise( | |
144 | + (id) => customerService.getCustomer(id, config), entityIds); | |
143 | 145 | break; |
144 | 146 | case types.entityType.rule: |
145 | - promise = getEntitiesByIdsPromise(ruleService.getRule, entityIds); | |
147 | + promise = getEntitiesByIdsPromise( | |
148 | + (id) => ruleService.getRule(id, config), entityIds); | |
146 | 149 | break; |
147 | 150 | case types.entityType.plugin: |
148 | - promise = getEntitiesByIdsPromise(pluginService.getPlugin, entityIds); | |
151 | + promise = getEntitiesByIdsPromise( | |
152 | + (id) => pluginService.getPlugin(id, config), entityIds); | |
149 | 153 | break; |
150 | 154 | case types.entityType.dashboard: |
151 | - promise = getEntitiesByIdsPromise(dashboardService.getDashboardInfo, entityIds); | |
155 | + promise = getEntitiesByIdsPromise( | |
156 | + (id) => dashboardService.getDashboardInfo(id, config), entityIds); | |
152 | 157 | break; |
153 | 158 | case types.entityType.user: |
154 | - promise = getEntitiesByIdsPromise(userService.getUser, entityIds); | |
159 | + promise = getEntitiesByIdsPromise( | |
160 | + (id) => userService.getUser(id, true, config), entityIds); | |
155 | 161 | break; |
156 | 162 | case types.entityType.alarm: |
157 | 163 | $log.error('Get Alarm Entity is not implemented!'); |
... | ... | @@ -178,11 +184,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
178 | 184 | return deferred.promise; |
179 | 185 | } |
180 | 186 | |
181 | - function getSingleTenantByPageLinkPromise(pageLink) { | |
187 | + function getSingleTenantByPageLinkPromise(pageLink, config) { | |
182 | 188 | var user = userService.getCurrentUser(); |
183 | 189 | var tenantId = user.tenantId; |
184 | 190 | var deferred = $q.defer(); |
185 | - tenantService.getTenant(tenantId).then( | |
191 | + tenantService.getTenant(tenantId, config).then( | |
186 | 192 | function success(tenant) { |
187 | 193 | var tenantName = tenant.name; |
188 | 194 | var result = { |
... | ... | @@ -202,11 +208,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
202 | 208 | return deferred.promise; |
203 | 209 | } |
204 | 210 | |
205 | - function getSingleCustomerByPageLinkPromise(pageLink) { | |
211 | + function getSingleCustomerByPageLinkPromise(pageLink, config) { | |
206 | 212 | var user = userService.getCurrentUser(); |
207 | 213 | var customerId = user.customerId; |
208 | 214 | var deferred = $q.defer(); |
209 | - customerService.getCustomer(customerId).then( | |
215 | + customerService.getCustomer(customerId, config).then( | |
210 | 216 | function success(customer) { |
211 | 217 | var customerName = customer.name; |
212 | 218 | var result = { |
... | ... | @@ -247,29 +253,29 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
247 | 253 | break; |
248 | 254 | case types.entityType.tenant: |
249 | 255 | if (user.authority === 'TENANT_ADMIN') { |
250 | - promise = getSingleTenantByPageLinkPromise(pageLink); | |
256 | + promise = getSingleTenantByPageLinkPromise(pageLink, config); | |
251 | 257 | } else { |
252 | - promise = tenantService.getTenants(pageLink); | |
258 | + promise = tenantService.getTenants(pageLink, config); | |
253 | 259 | } |
254 | 260 | break; |
255 | 261 | case types.entityType.customer: |
256 | 262 | if (user.authority === 'CUSTOMER_USER') { |
257 | - promise = getSingleCustomerByPageLinkPromise(pageLink); | |
263 | + promise = getSingleCustomerByPageLinkPromise(pageLink, config); | |
258 | 264 | } else { |
259 | - promise = customerService.getCustomers(pageLink); | |
265 | + promise = customerService.getCustomers(pageLink, config); | |
260 | 266 | } |
261 | 267 | break; |
262 | 268 | case types.entityType.rule: |
263 | - promise = ruleService.getAllRules(pageLink); | |
269 | + promise = ruleService.getAllRules(pageLink, config); | |
264 | 270 | break; |
265 | 271 | case types.entityType.plugin: |
266 | - promise = pluginService.getAllPlugins(pageLink); | |
272 | + promise = pluginService.getAllPlugins(pageLink, config); | |
267 | 273 | break; |
268 | 274 | case types.entityType.dashboard: |
269 | 275 | if (user.authority === 'CUSTOMER_USER') { |
270 | - promise = dashboardService.getCustomerDashboards(customerId, pageLink, false); | |
276 | + promise = dashboardService.getCustomerDashboards(customerId, pageLink, false, config); | |
271 | 277 | } else { |
272 | - promise = dashboardService.getTenantDashboards(pageLink, false); | |
278 | + promise = dashboardService.getTenantDashboards(pageLink, false, config); | |
273 | 279 | } |
274 | 280 | break; |
275 | 281 | case types.entityType.user: |
... | ... | @@ -426,7 +432,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
426 | 432 | var stateEntityId = getStateEntityId(filter, stateParams); |
427 | 433 | switch (filter.type) { |
428 | 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 | 436 | function success(entity) { |
431 | 437 | result.entities = entitiesToEntitiesInfo([entity]); |
432 | 438 | deferred.resolve(result); |
... | ... | @@ -437,7 +443,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
437 | 443 | ); |
438 | 444 | break; |
439 | 445 | case types.aliasFilterType.entityList.value: |
440 | - getEntities(filter.entityType, filter.entityList).then( | |
446 | + getEntities(filter.entityType, filter.entityList, {ignoreLoading: true}).then( | |
441 | 447 | function success(entities) { |
442 | 448 | if (entities && entities.length || !failOnEmpty) { |
443 | 449 | result.entities = entitiesToEntitiesInfo(entities); |
... | ... | @@ -452,7 +458,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
452 | 458 | ); |
453 | 459 | break; |
454 | 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 | 462 | function success(entities) { |
457 | 463 | if (entities && entities.length || !failOnEmpty) { |
458 | 464 | result.entities = entitiesToEntitiesInfo(entities); |
... | ... | @@ -469,7 +475,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
469 | 475 | case types.aliasFilterType.stateEntity.value: |
470 | 476 | result.stateEntity = true; |
471 | 477 | if (stateEntityId) { |
472 | - getEntity(stateEntityId.entityType, stateEntityId.id).then( | |
478 | + getEntity(stateEntityId.entityType, stateEntityId.id, {ignoreLoading: true}).then( | |
473 | 479 | function success(entity) { |
474 | 480 | result.entities = entitiesToEntitiesInfo([entity]); |
475 | 481 | deferred.resolve(result); |
... | ... | @@ -483,7 +489,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
483 | 489 | } |
484 | 490 | break; |
485 | 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 | 493 | function success(entities) { |
488 | 494 | if (entities && entities.length || !failOnEmpty) { |
489 | 495 | result.entities = entitiesToEntitiesInfo(entities); |
... | ... | @@ -498,7 +504,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
498 | 504 | ); |
499 | 505 | break; |
500 | 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 | 508 | function success(entities) { |
503 | 509 | if (entities && entities.length || !failOnEmpty) { |
504 | 510 | result.entities = entitiesToEntitiesInfo(entities); |
... | ... | @@ -533,7 +539,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
533 | 539 | filters: filter.filters |
534 | 540 | }; |
535 | 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 | 543 | function success(allRelations) { |
538 | 544 | if (allRelations && allRelations.length || !failOnEmpty) { |
539 | 545 | if (angular.isDefined(maxItems) && maxItems > 0 && allRelations) { |
... | ... | @@ -577,10 +583,10 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
577 | 583 | var findByQueryPromise; |
578 | 584 | if (filter.type == types.aliasFilterType.assetSearchQuery.value) { |
579 | 585 | searchQuery.assetTypes = filter.assetTypes; |
580 | - findByQueryPromise = assetService.findByQuery(searchQuery, false); | |
586 | + findByQueryPromise = assetService.findByQuery(searchQuery, false, {ignoreLoading: true}); | |
581 | 587 | } else if (filter.type == types.aliasFilterType.deviceSearchQuery.value) { |
582 | 588 | searchQuery.deviceTypes = filter.deviceTypes; |
583 | - findByQueryPromise = deviceService.findByQuery(searchQuery, false); | |
589 | + findByQueryPromise = deviceService.findByQuery(searchQuery, false, {ignoreLoading: true}); | |
584 | 590 | } |
585 | 591 | findByQueryPromise.then( |
586 | 592 | function success(entities) { |
... | ... | @@ -762,7 +768,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
762 | 768 | return deferred.promise; |
763 | 769 | } |
764 | 770 | |
765 | - function getEntityKeys(entityType, entityId, query, type) { | |
771 | + function getEntityKeys(entityType, entityId, query, type, config) { | |
766 | 772 | var deferred = $q.defer(); |
767 | 773 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; |
768 | 774 | if (type === types.dataKeyType.timeseries) { |
... | ... | @@ -770,7 +776,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
770 | 776 | } else if (type === types.dataKeyType.attribute) { |
771 | 777 | url += 'attributes'; |
772 | 778 | } |
773 | - $http.get(url, null).then(function success(response) { | |
779 | + $http.get(url, config).then(function success(response) { | |
774 | 780 | var result = []; |
775 | 781 | if (response.data) { |
776 | 782 | if (query) { | ... | ... |
... | ... | @@ -50,11 +50,11 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic |
50 | 50 | tenantPlugins = undefined; |
51 | 51 | } |
52 | 52 | |
53 | - function loadPluginsCache() { | |
53 | + function loadPluginsCache(config) { | |
54 | 54 | var deferred = $q.defer(); |
55 | 55 | if (!allPlugins) { |
56 | 56 | var url = '/api/plugins'; |
57 | - $http.get(url, null).then(function success(response) { | |
57 | + $http.get(url, config).then(function success(response) { | |
58 | 58 | componentDescriptorService.getComponentDescriptorsByType(types.componentType.plugin).then( |
59 | 59 | function success(pluginComponents) { |
60 | 60 | allPlugins = response.data; |
... | ... | @@ -93,9 +93,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic |
93 | 93 | return deferred.promise; |
94 | 94 | } |
95 | 95 | |
96 | - function getSystemPlugins(pageLink) { | |
96 | + function getSystemPlugins(pageLink, config) { | |
97 | 97 | var deferred = $q.defer(); |
98 | - loadPluginsCache().then( | |
98 | + loadPluginsCache(config).then( | |
99 | 99 | function success() { |
100 | 100 | utils.filterSearchTextEntities(systemPlugins, 'name', pageLink, deferred); |
101 | 101 | }, |
... | ... | @@ -106,9 +106,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic |
106 | 106 | return deferred.promise; |
107 | 107 | } |
108 | 108 | |
109 | - function getTenantPlugins(pageLink) { | |
109 | + function getTenantPlugins(pageLink, config) { | |
110 | 110 | var deferred = $q.defer(); |
111 | - loadPluginsCache().then( | |
111 | + loadPluginsCache(config).then( | |
112 | 112 | function success() { |
113 | 113 | utils.filterSearchTextEntities(tenantPlugins, 'name', pageLink, deferred); |
114 | 114 | }, |
... | ... | @@ -119,9 +119,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic |
119 | 119 | return deferred.promise; |
120 | 120 | } |
121 | 121 | |
122 | - function getAllActionPlugins(pageLink) { | |
122 | + function getAllActionPlugins(pageLink, config) { | |
123 | 123 | var deferred = $q.defer(); |
124 | - loadPluginsCache().then( | |
124 | + loadPluginsCache(config).then( | |
125 | 125 | function success() { |
126 | 126 | utils.filterSearchTextEntities(allActionPlugins, 'name', pageLink, deferred); |
127 | 127 | }, |
... | ... | @@ -132,9 +132,9 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic |
132 | 132 | return deferred.promise; |
133 | 133 | } |
134 | 134 | |
135 | - function getAllPlugins(pageLink) { | |
135 | + function getAllPlugins(pageLink, config) { | |
136 | 136 | var deferred = $q.defer(); |
137 | - loadPluginsCache().then( | |
137 | + loadPluginsCache(config).then( | |
138 | 138 | function success() { |
139 | 139 | utils.filterSearchTextEntities(allPlugins, 'name', pageLink, deferred); |
140 | 140 | }, |
... | ... | @@ -156,10 +156,10 @@ function PluginService($http, $q, $rootScope, $filter, componentDescriptorServic |
156 | 156 | return deferred.promise; |
157 | 157 | } |
158 | 158 | |
159 | - function getPlugin(pluginId) { | |
159 | + function getPlugin(pluginId, config) { | |
160 | 160 | var deferred = $q.defer(); |
161 | 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 | 163 | deferred.resolve(response.data); |
164 | 164 | }, function fail(response) { |
165 | 165 | deferred.reject(response.data); | ... | ... |
... | ... | @@ -47,11 +47,11 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) { |
47 | 47 | tenantRules = undefined; |
48 | 48 | } |
49 | 49 | |
50 | - function loadRulesCache() { | |
50 | + function loadRulesCache(config) { | |
51 | 51 | var deferred = $q.defer(); |
52 | 52 | if (!allRules) { |
53 | 53 | var url = '/api/rules'; |
54 | - $http.get(url, null).then(function success(response) { | |
54 | + $http.get(url, config).then(function success(response) { | |
55 | 55 | allRules = response.data; |
56 | 56 | systemRules = []; |
57 | 57 | tenantRules = []; |
... | ... | @@ -100,9 +100,9 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) { |
100 | 100 | return deferred.promise; |
101 | 101 | } |
102 | 102 | |
103 | - function getAllRules(pageLink) { | |
103 | + function getAllRules(pageLink, config) { | |
104 | 104 | var deferred = $q.defer(); |
105 | - loadRulesCache().then( | |
105 | + loadRulesCache(config).then( | |
106 | 106 | function success() { |
107 | 107 | utils.filterSearchTextEntities(allRules, 'name', pageLink, deferred); |
108 | 108 | }, |
... | ... | @@ -124,10 +124,10 @@ function RuleService($http, $q, $rootScope, $filter, types, utils) { |
124 | 124 | return deferred.promise; |
125 | 125 | } |
126 | 126 | |
127 | - function getRule(ruleId) { | |
127 | + function getRule(ruleId, config) { | |
128 | 128 | var deferred = $q.defer(); |
129 | 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 | 131 | deferred.resolve(response.data); |
132 | 132 | }, function fail(response) { |
133 | 133 | deferred.reject(response.data); | ... | ... |
... | ... | @@ -23,6 +23,8 @@ export default angular.module('thingsboard.api.telemetryWebsocket', [thingsboard |
23 | 23 | const RECONNECT_INTERVAL = 2000; |
24 | 24 | const WS_IDLE_TIMEOUT = 90000; |
25 | 25 | |
26 | +const MAX_PUBLISH_COMMANDS = 10; | |
27 | + | |
26 | 28 | /*@ngInject*/ |
27 | 29 | function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, types, userService) { |
28 | 30 | |
... | ... | @@ -75,19 +77,40 @@ function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, ty |
75 | 77 | return service; |
76 | 78 | |
77 | 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 | 82 | checkToClose(); |
83 | 83 | }); |
84 | - cmdsWrapper.tsSubCmds = []; | |
85 | - cmdsWrapper.historyCmds = []; | |
86 | - cmdsWrapper.attrSubCmds = []; | |
87 | 84 | } |
88 | 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 | 114 | function onError (/*message*/) { |
92 | 115 | isOpening = false; |
93 | 116 | } | ... | ... |
... | ... | @@ -29,7 +29,7 @@ function TenantService($http, $q) { |
29 | 29 | |
30 | 30 | return service; |
31 | 31 | |
32 | - function getTenants (pageLink) { | |
32 | + function getTenants (pageLink, config) { | |
33 | 33 | var deferred = $q.defer(); |
34 | 34 | var url = '/api/tenants?limit=' + pageLink.limit; |
35 | 35 | if (angular.isDefined(pageLink.textSearch)) { |
... | ... | @@ -41,7 +41,7 @@ function TenantService($http, $q) { |
41 | 41 | if (angular.isDefined(pageLink.textOffset)) { |
42 | 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 | 45 | deferred.resolve(response.data); |
46 | 46 | }, function fail() { |
47 | 47 | deferred.reject(); |
... | ... | @@ -49,10 +49,10 @@ function TenantService($http, $q) { |
49 | 49 | return deferred.promise; |
50 | 50 | } |
51 | 51 | |
52 | - function getTenant (tenantId) { | |
52 | + function getTenant (tenantId, config) { | |
53 | 53 | var deferred = $q.defer(); |
54 | 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 | 56 | deferred.resolve(response.data); |
57 | 57 | }, function fail(response) { |
58 | 58 | deferred.reject(response.data); | ... | ... |
... | ... | @@ -421,10 +421,14 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi |
421 | 421 | return deferred.promise; |
422 | 422 | } |
423 | 423 | |
424 | - function getUser(userId, ignoreErrors) { | |
424 | + function getUser(userId, ignoreErrors, config) { | |
425 | 425 | var deferred = $q.defer(); |
426 | 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 | 432 | deferred.resolve(response.data); |
429 | 433 | }, function fail() { |
430 | 434 | deferred.reject(); | ... | ... |
... | ... | @@ -298,11 +298,11 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr |
298 | 298 | tenantWidgetsBundles = undefined; |
299 | 299 | } |
300 | 300 | |
301 | - function loadWidgetsBundleCache() { | |
301 | + function loadWidgetsBundleCache(config) { | |
302 | 302 | var deferred = $q.defer(); |
303 | 303 | if (!allWidgetsBundles) { |
304 | 304 | var url = '/api/widgetsBundles'; |
305 | - $http.get(url, null).then(function success(response) { | |
305 | + $http.get(url, config).then(function success(response) { | |
306 | 306 | allWidgetsBundles = response.data; |
307 | 307 | systemWidgetsBundles = []; |
308 | 308 | tenantWidgetsBundles = []; |
... | ... | @@ -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 | 330 | var deferred = $q.defer(); |
331 | - loadWidgetsBundleCache().then( | |
331 | + loadWidgetsBundleCache(config).then( | |
332 | 332 | function success() { |
333 | 333 | deferred.resolve(systemWidgetsBundles); |
334 | 334 | }, |
... | ... | @@ -339,9 +339,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr |
339 | 339 | return deferred.promise; |
340 | 340 | } |
341 | 341 | |
342 | - function getTenantWidgetsBundles() { | |
342 | + function getTenantWidgetsBundles(config) { | |
343 | 343 | var deferred = $q.defer(); |
344 | - loadWidgetsBundleCache().then( | |
344 | + loadWidgetsBundleCache(config).then( | |
345 | 345 | function success() { |
346 | 346 | deferred.resolve(tenantWidgetsBundles); |
347 | 347 | }, |
... | ... | @@ -352,9 +352,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr |
352 | 352 | return deferred.promise; |
353 | 353 | } |
354 | 354 | |
355 | - function getAllWidgetsBundles() { | |
355 | + function getAllWidgetsBundles(config) { | |
356 | 356 | var deferred = $q.defer(); |
357 | - loadWidgetsBundleCache().then( | |
357 | + loadWidgetsBundleCache(config).then( | |
358 | 358 | function success() { |
359 | 359 | deferred.resolve(allWidgetsBundles); |
360 | 360 | }, | ... | ... |
... | ... | @@ -27,8 +27,8 @@ |
27 | 27 | </md-button> |
28 | 28 | </div> |
29 | 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 | 32 | <md-dialog-content> |
33 | 33 | <div class="md-dialog-content"> |
34 | 34 | <tb-asset asset="vm.item" is-edit="true" the-form="theForm"></tb-asset> |
... | ... | @@ -36,10 +36,10 @@ |
36 | 36 | </md-dialog-content> |
37 | 37 | <md-dialog-actions layout="row"> |
38 | 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 | 40 | {{ 'action.add' | translate }} |
41 | 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 | 43 | </md-dialog-actions> |
44 | 44 | </form> |
45 | 45 | </md-dialog> | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset> |
... | ... | @@ -65,11 +65,11 @@ |
65 | 65 | </md-dialog-content> |
66 | 66 | <md-dialog-actions layout="row"> |
67 | 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 | 69 | class="md-raised md-primary"> |
70 | 70 | {{ 'action.assign' | translate }} |
71 | 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 | 73 | translate }} |
74 | 74 | </md-button> |
75 | 75 | </md-dialog-actions> | ... | ... |
... | ... | @@ -48,7 +48,7 @@ |
48 | 48 | ng-show="!isEdit && isPublic && (assetScope === 'customer' || assetScope === 'tenant')"> |
49 | 49 | {{ 'asset.asset-public' | translate }} |
50 | 50 | </div> |
51 | - <fieldset ng-disabled="loading || !isEdit"> | |
51 | + <fieldset ng-disabled="$root.loading || !isEdit"> | |
52 | 52 | <md-input-container class="md-block"> |
53 | 53 | <label translate>asset.name</label> |
54 | 54 | <input required name="name" ng-model="asset.name"> |
... | ... | @@ -57,7 +57,7 @@ |
57 | 57 | </div> |
58 | 58 | </md-input-container> |
59 | 59 | <tb-entity-subtype-autocomplete |
60 | - ng-disabled="loading || !isEdit" | |
60 | + ng-disabled="$root.loading || !isEdit" | |
61 | 61 | tb-required="true" |
62 | 62 | the-form="theForm" |
63 | 63 | ng-model="asset.type" | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset> |
... | ... | @@ -65,10 +65,10 @@ |
65 | 65 | </md-dialog-content> |
66 | 66 | <md-dialog-actions layout="row"> |
67 | 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 | 69 | {{ 'action.assign' | translate }} |
70 | 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 | 72 | translate }} |
73 | 73 | </md-button> |
74 | 74 | </md-dialog-actions> | ... | ... |
... | ... | @@ -134,6 +134,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t |
134 | 134 | defaultAlarmDataKeys.push(dataKey); |
135 | 135 | } |
136 | 136 | |
137 | + var imageAspectMap = {}; | |
138 | + | |
137 | 139 | var service = { |
138 | 140 | getDefaultDatasource: getDefaultDatasource, |
139 | 141 | generateObjectFromJsonSchema: generateObjectFromJsonSchema, |
... | ... | @@ -159,7 +161,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t |
159 | 161 | insertVariable: insertVariable, |
160 | 162 | customTranslation: customTranslation, |
161 | 163 | objToBase64: objToBase64, |
162 | - base64toObj: base64toObj | |
164 | + base64toObj: base64toObj, | |
165 | + loadImageAspect: loadImageAspect | |
163 | 166 | } |
164 | 167 | |
165 | 168 | return service; |
... | ... | @@ -543,4 +546,34 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t |
543 | 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 | 27 | </md-button> |
28 | 28 | </div> |
29 | 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 | 32 | <md-dialog-content> |
33 | 33 | <div class="md-dialog-content tb-filter"> |
34 | - <fieldset ng-disabled="loading || vm.isReadOnly"> | |
34 | + <fieldset ng-disabled="$root.loading || vm.isReadOnly"> | |
35 | 35 | <section flex layout="row"> |
36 | 36 | <md-input-container flex class="md-block"> |
37 | 37 | <label translate>rule.component-name</label> |
... | ... | @@ -42,7 +42,7 @@ |
42 | 42 | </md-input-container> |
43 | 43 | <md-input-container flex class="md-block"> |
44 | 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 | 46 | <md-option ng-repeat="componentDescriptor in vm.componentDescriptors" ng-value="componentDescriptor.clazz"> |
47 | 47 | {{componentDescriptor.name}} |
48 | 48 | </md-option> |
... | ... | @@ -57,7 +57,7 @@ |
57 | 57 | <tb-json-form schema="vm.componentDescriptor.configurationDescriptor.schema" |
58 | 58 | form="vm.componentDescriptor.configurationDescriptor.form" |
59 | 59 | model="vm.componentInfo.component.configuration" |
60 | - readonly="loading || vm.isReadOnly" | |
60 | + readonly="$root.loading || vm.isReadOnly" | |
61 | 61 | form-control="theForm"> |
62 | 62 | </tb-json-form> |
63 | 63 | </md-card-content> |
... | ... | @@ -67,11 +67,11 @@ |
67 | 67 | </md-dialog-content> |
68 | 68 | <md-dialog-actions layout="row"> |
69 | 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 | 71 | class="md-raised md-primary"> |
72 | 72 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} |
73 | 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 | 75 | translate }} |
76 | 76 | </md-button> |
77 | 77 | </md-dialog-actions> | ... | ... |
... | ... | @@ -24,7 +24,7 @@ |
24 | 24 | {{ componentTypeName }} |
25 | 25 | </span> |
26 | 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 | 28 | style="min-width: 40px;" |
29 | 29 | ng-click="openComponent($event)" |
30 | 30 | aria-label="{{ (readOnly ? 'action.view' : 'action.edit') | translate }}"> |
... | ... | @@ -43,7 +43,7 @@ |
43 | 43 | edit |
44 | 44 | </md-icon> |
45 | 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 | 47 | style="min-width: 40px;" |
48 | 48 | ng-click="onRemoveComponent({event: $event})" |
49 | 49 | aria-label="{{ 'action.remove' | translate }}"> | ... | ... |
... | ... | @@ -48,19 +48,19 @@ function DashboardAutocomplete($compile, $templateCache, $q, dashboardService, u |
48 | 48 | var promise; |
49 | 49 | if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') { |
50 | 50 | if (scope.customerId) { |
51 | - promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false); | |
51 | + promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false, {ignoreLoading: true}); | |
52 | 52 | } else { |
53 | 53 | promise = $q.when({data: []}); |
54 | 54 | } |
55 | 55 | } else { |
56 | 56 | if (userService.getAuthority() === 'SYS_ADMIN') { |
57 | 57 | if (scope.tenantId) { |
58 | - promise = dashboardService.getTenantDashboardsByTenantId(scope.tenantId, pageLink); | |
58 | + promise = dashboardService.getTenantDashboardsByTenantId(scope.tenantId, pageLink, {ignoreLoading: true}); | |
59 | 59 | } else { |
60 | 60 | promise = $q.when({data: []}); |
61 | 61 | } |
62 | 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 | 48 | var promise; |
49 | 49 | if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') { |
50 | 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 | 52 | } else { |
53 | 53 | promise = $q.when({data: []}); |
54 | 54 | } |
55 | 55 | } else { |
56 | - promise = dashboardService.getTenantDashboards(pageLink, false); | |
56 | + promise = dashboardService.getTenantDashboards(pageLink, false, {ignoreLoading: true}); | |
57 | 57 | } |
58 | 58 | |
59 | 59 | promise.then(function success(result) { | ... | ... |
... | ... | @@ -43,7 +43,7 @@ function DatakeyConfigDialogController($scope, $mdDialog, $q, entityService, dat |
43 | 43 | function success(aliasInfo) { |
44 | 44 | var entity = aliasInfo.currentEntity; |
45 | 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 | 47 | function success(keys) { |
48 | 48 | deferred.resolve(keys); |
49 | 49 | }, | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <tb-datakey-config ng-model="vm.dataKey" |
33 | 33 | fetch-entity-keys="vm.fetchEntityKeys(entityAliasId, query, type)" |
... | ... | @@ -37,10 +37,10 @@ |
37 | 37 | </md-dialog-content> |
38 | 38 | <md-dialog-actions layout="row"> |
39 | 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 | 41 | {{ 'action.save' | translate }} |
42 | 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 | 44 | </md-dialog-actions> |
45 | 45 | </form> |
46 | 46 | </md-dialog> | ... | ... |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | </div> |
36 | 36 | <section ng-if="!isReadOnly" layout="row" layout-wrap |
37 | 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 | 39 | class="tb-btn-header md-accent md-hue-2 md-fab md-fab-bottom-right" |
40 | 40 | aria-label="{{ 'action.apply' | translate }}" |
41 | 41 | ng-click="detailsApply()"> |
... | ... | @@ -44,7 +44,7 @@ |
44 | 44 | </md-tooltip> |
45 | 45 | <ng-md-icon icon="done"></ng-md-icon> |
46 | 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 | 48 | aria-label="{{ 'details.edit-mode' | translate }}" |
49 | 49 | ng-click="toggleDetailsEditMode()"> |
50 | 50 | <md-tooltip md-direction="top"> | ... | ... |
... | ... | @@ -45,7 +45,7 @@ |
45 | 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 | 46 | </md-card-content> |
47 | 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 | 49 | ng-click="action.onAction($event, rowItem[n])" aria-label="{{ action.name() }}"> |
50 | 50 | <md-tooltip md-direction="top"> |
51 | 51 | {{ action.details( rowItem[n] ) }} |
... | ... | @@ -81,28 +81,28 @@ |
81 | 81 | </section> |
82 | 82 | |
83 | 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 | 85 | ng-click="groupAction.onAction($event, vm.items)" aria-label="{{ groupAction.name() }}"> |
86 | 86 | <md-tooltip md-direction="top"> |
87 | 87 | {{ groupAction.details(vm.items.selectedCount) }} |
88 | 88 | </md-tooltip> |
89 | 89 | <ng-md-icon icon="{{groupAction.icon}}"></ng-md-icon> |
90 | 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 | 92 | <md-tooltip md-direction="top"> |
93 | 93 | {{'grid.scroll-to-top' | translate}} |
94 | 94 | </md-tooltip> |
95 | 95 | <ng-md-icon icon="arrow_drop_up"></ng-md-icon> |
96 | 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 | 98 | <md-tooltip md-direction="top"> |
99 | 99 | {{ vm.addItemAction.details() }} |
100 | 100 | </md-tooltip> |
101 | 101 | <ng-md-icon icon="{{ vm.addItemAction.icon }}"></ng-md-icon> |
102 | 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 | 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 | 106 | <md-tooltip md-direction="top"> |
107 | 107 | {{ vm.addItemAction.details() }} |
108 | 108 | </md-tooltip> |
... | ... | @@ -110,7 +110,7 @@ |
110 | 110 | </md-button> |
111 | 111 | </md-fab-trigger> |
112 | 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 | 114 | ng-click="addItemAction.onAction($event)" aria-label="{{ addItemAction.name() }}" > |
115 | 115 | <md-tooltip md-direction="top"> |
116 | 116 | {{ addItemAction.details() }} | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | |
17 | 17 | --> |
18 | 18 | <form name="theForm" ng-submit="vm.update()"> |
19 | - <fieldset ng-disabled="loading"> | |
19 | + <fieldset ng-disabled="$root.loading"> | |
20 | 20 | <md-content style="height: 100%" flex layout="column"> |
21 | 21 | <section layout="column"> |
22 | 22 | <md-content class="md-padding" layout="column"> | ... | ... |
... | ... | @@ -32,15 +32,15 @@ |
32 | 32 | </md-button> |
33 | 33 | </div> |
34 | 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 | 37 | <div class="tb-absolute-fill tb-icons-load" ng-show="vm.loadingIcons" layout="column" layout-align="center center"> |
38 | 38 | <md-progress-circular md-mode="indeterminate" ng-disabled="!vm.loadingIcons" class="md-accent" md-diameter="40"></md-progress-circular> |
39 | 39 | </div> |
40 | 40 | <md-dialog-content> |
41 | 41 | <div class="md-dialog-content"> |
42 | 42 | <md-content class="md-padding" layout="column"> |
43 | - <fieldset ng-disabled="loading"> | |
43 | + <fieldset ng-disabled="$root.loading"> | |
44 | 44 | <md-button ng-class="{'md-primary md-raised': icon == vm.selectedIcon}" class="tb-select-icon-button md-icon-button" |
45 | 45 | ng-repeat="icon in vm.icons" ng-click="vm.selectIcon($event, icon)" tb-on-finish-render="iconsLoadFinished"> |
46 | 46 | <md-icon class="material-icons">{{icon}}</md-icon> |
... | ... | @@ -54,7 +54,7 @@ |
54 | 54 | </md-dialog-content> |
55 | 55 | <md-dialog-actions layout="row"> |
56 | 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 | 58 | {{ 'action.cancel' | translate }} |
59 | 59 | </md-button> |
60 | 60 | </md-dialog-actions> | ... | ... |
... | ... | @@ -56,7 +56,7 @@ function PluginSelect($compile, $templateCache, $q, pluginService, types) { |
56 | 56 | |
57 | 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 | 60 | deferred.resolve(result.data); |
61 | 61 | }, function fail() { |
62 | 62 | deferred.reject(); |
... | ... | @@ -89,7 +89,7 @@ function PluginSelect($compile, $templateCache, $q, pluginService, types) { |
89 | 89 | |
90 | 90 | if (scope.selectFirstPlugin) { |
91 | 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 | 93 | var plugins = result.data; |
94 | 94 | if (plugins.length > 0) { |
95 | 95 | scope.plugin = plugins[0]; | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | |
17 | 17 | --> |
18 | 18 | <form name="theForm" ng-submit="vm.update()"> |
19 | - <fieldset ng-disabled="loading"> | |
19 | + <fieldset ng-disabled="$root.loading"> | |
20 | 20 | <md-content style="height: 100%" flex layout="column"> |
21 | 21 | <section layout="column"> |
22 | 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 | 81 | <span flex></span> |
82 | 82 | <section layout="row" layout-alignment="start center"> |
83 | 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 | 85 | {{ 'action.update' | translate }} |
86 | 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 | 88 | {{ 'action.cancel' | translate }} |
89 | 89 | </md-button> |
90 | 90 | </section> | ... | ... |
... | ... | @@ -26,12 +26,12 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <md-content class="md-padding" layout="column"> |
34 | - <fieldset ng-disabled="loading" layout="column"> | |
34 | + <fieldset ng-disabled="$root.loading" layout="column"> | |
35 | 35 | <md-input-container class="md-block"> |
36 | 36 | <label translate>widget-config.action-source</label> |
37 | 37 | <md-select name="actionSource" required aria-label="{{ 'widget-config.action-source' | translate }}" ng-model="vm.action.actionSourceId"> |
... | ... | @@ -120,7 +120,7 @@ |
120 | 120 | </div> |
121 | 121 | <tb-js-func ng-if="vm.action.type == vm.types.widgetActionTypes.custom.value" |
122 | 122 | ng-model="vm.action.customFunction" |
123 | - function-args="{{ ['$event', 'widgetContext', 'entityId'] }}" | |
123 | + function-args="{{ ['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams'] }}" | |
124 | 124 | validation-args="{{ [] }}"> |
125 | 125 | </tb-js-func> |
126 | 126 | </fieldset> |
... | ... | @@ -129,11 +129,11 @@ |
129 | 129 | </md-dialog-content> |
130 | 130 | <md-dialog-actions layout="row"> |
131 | 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 | 133 | class="md-raised md-primary"> |
134 | 134 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} |
135 | 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 | 137 | {{ 'action.cancel' | translate }} |
138 | 138 | </md-button> |
139 | 139 | </md-dialog-actions> | ... | ... |
... | ... | @@ -104,7 +104,7 @@ |
104 | 104 | generate-data-key="generateDataKey(chip,type)" |
105 | 105 | fetch-entity-keys="fetchEntityKeys({entityAliasId: entityAliasId, query: query, type: type})" |
106 | 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 | 108 | style="min-width: 40px;" |
109 | 109 | ng-click="removeDatasource($event, datasource)" |
110 | 110 | aria-label="{{ 'action.remove' | translate }}"> |
... | ... | @@ -121,7 +121,7 @@ |
121 | 121 | </div> |
122 | 122 | </div> |
123 | 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 | 125 | ng-click="addDatasource($event)" aria-label="{{ 'action.add' | translate }}"> |
126 | 126 | <md-tooltip md-direction="top"> |
127 | 127 | {{ 'widget-config.add-datasource' | translate }} | ... | ... |
... | ... | @@ -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 | 448 | var type = descriptor.type; |
449 | 449 | var targetEntityParamName = descriptor.stateEntityParamName; |
450 | 450 | var targetEntityId; |
... | ... | @@ -485,8 +485,11 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele |
485 | 485 | var customFunction = descriptor.customFunction; |
486 | 486 | if (angular.isDefined(customFunction) && customFunction.length > 0) { |
487 | 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 | 493 | } catch (e) { |
491 | 494 | // |
492 | 495 | } | ... | ... |
... | ... | @@ -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 | 52 | function success(widgetsBundles) { |
53 | 53 | scope.widgetsBundles = widgetsBundles; |
54 | 54 | if (scope.selectFirstBundle) { | ... | ... |
... | ... | @@ -27,8 +27,8 @@ |
27 | 27 | </md-button> |
28 | 28 | </div> |
29 | 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 | 32 | <md-dialog-content> |
33 | 33 | <div class="md-dialog-content"> |
34 | 34 | <tb-customer customer="vm.item" is-edit="true" the-form="theForm"></tb-customer> |
... | ... | @@ -36,10 +36,10 @@ |
36 | 36 | </md-dialog-content> |
37 | 37 | <md-dialog-actions layout="row"> |
38 | 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 | 40 | {{ 'action.add' | translate }} |
41 | 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 | 43 | </md-dialog-actions> |
44 | 44 | </form> |
45 | 45 | </md-dialog> | ... | ... |
... | ... | @@ -32,7 +32,7 @@ |
32 | 32 | </div> |
33 | 33 | |
34 | 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 | 36 | <md-input-container class="md-block"> |
37 | 37 | <label translate>customer.title</label> |
38 | 38 | <input required name="title" ng-model="customer.title"> | ... | ... |
... | ... | @@ -27,8 +27,8 @@ |
27 | 27 | </md-button> |
28 | 28 | </div> |
29 | 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 | 32 | <md-dialog-content> |
33 | 33 | <div class="md-dialog-content"> |
34 | 34 | <tb-dashboard-details dashboard="vm.item" is-edit="true" the-form="theForm"></tb-dashboard-details> |
... | ... | @@ -36,10 +36,10 @@ |
36 | 36 | </md-dialog-content> |
37 | 37 | <md-dialog-actions layout="row"> |
38 | 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 | 40 | {{ 'action.add' | translate }} |
41 | 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 | 43 | </md-dialog-actions> |
44 | 44 | </form> |
45 | 45 | </md-dialog> |
\ No newline at end of file | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset> |
... | ... | @@ -65,11 +65,11 @@ |
65 | 65 | </md-dialog-content> |
66 | 66 | <md-dialog-actions layout="row"> |
67 | 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 | 69 | class="md-raised md-primary"> |
70 | 70 | {{ 'action.assign' | translate }} |
71 | 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 | 73 | translate }} |
74 | 74 | </md-button> |
75 | 75 | </md-dialog-actions> | ... | ... |
... | ... | @@ -110,7 +110,7 @@ export default function AddWidgetController($scope, widgetService, entityService |
110 | 110 | function success(aliasInfo) { |
111 | 111 | var entity = aliasInfo.currentEntity; |
112 | 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 | 114 | function success(keys) { |
115 | 115 | deferred.resolve(keys); |
116 | 116 | }, | ... | ... |
... | ... | @@ -27,11 +27,11 @@ |
27 | 27 | </md-button> |
28 | 28 | </div> |
29 | 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 | 32 | <md-dialog-content> |
33 | 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 | 35 | <tb-widget-config widget-type="vm.widget.type" |
36 | 36 | type-parameters="vm.widgetInfo.typeParameters" |
37 | 37 | action-sources="vm.widgetInfo.actionSources" |
... | ... | @@ -50,11 +50,11 @@ |
50 | 50 | </md-dialog-content> |
51 | 51 | <md-dialog-actions layout="row"> |
52 | 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 | 54 | class="md-raised md-primary"> |
55 | 55 | {{ 'action.add' | translate }} |
56 | 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 | 58 | translate }} |
59 | 59 | </md-button> |
60 | 60 | </md-dialog-actions> | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset> |
... | ... | @@ -65,10 +65,10 @@ |
65 | 65 | </md-dialog-content> |
66 | 66 | <md-dialog-actions layout="row"> |
67 | 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 | 69 | {{ 'action.assign' | translate }} |
70 | 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 | 72 | translate }} |
73 | 73 | </md-button> |
74 | 74 | </md-dialog-actions> | ... | ... |
... | ... | @@ -59,7 +59,7 @@ |
59 | 59 | </md-button> |
60 | 60 | </div> |
61 | 61 | </div> |
62 | - <fieldset ng-disabled="loading || !isEdit"> | |
62 | + <fieldset ng-disabled="$root.loading || !isEdit"> | |
63 | 63 | <md-input-container class="md-block"> |
64 | 64 | <label translate>dashboard.title</label> |
65 | 65 | <input required name="title" ng-model="dashboard.title"> | ... | ... |
... | ... | @@ -26,11 +26,11 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading"> | |
33 | + <fieldset ng-disabled="$root.loading"> | |
34 | 34 | <div ng-show="vm.settings"> |
35 | 35 | <md-input-container class="md-block"> |
36 | 36 | <label translate>dashboard.state-controller</label> |
... | ... | @@ -194,10 +194,10 @@ |
194 | 194 | </md-dialog-content> |
195 | 195 | <md-dialog-actions layout="row"> |
196 | 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 | 198 | {{ 'action.save' | translate }} |
199 | 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 | 201 | </md-dialog-actions> |
202 | 202 | </form> |
203 | 203 | </md-dialog> | ... | ... |
... | ... | @@ -110,7 +110,7 @@ |
110 | 110 | </section> |
111 | 111 | <section class="tb-dashboard-container tb-absolute-fill" |
112 | 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 | 114 | ng-style="{'color': vm.dashboard.configuration.settings.titleColor}" |
115 | 115 | ng-class="{'tb-padded' : !vm.widgetEditMode}" |
116 | 116 | style="text-transform: uppercase; display: flex; z-index: 1;" |
... | ... | @@ -277,10 +277,10 @@ |
277 | 277 | </div> |
278 | 278 | </tb-details-sidenav> |
279 | 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 | 281 | md-open="vm.addItemActionsOpen" class="md-scale" md-direction="up"> |
282 | 282 | <md-fab-trigger> |
283 | - <md-button ng-disabled="loading" | |
283 | + <md-button ng-disabled="$root.loading" | |
284 | 284 | class="tb-btn-footer md-accent md-hue-2 md-fab" |
285 | 285 | aria-label="{{ 'dashboard.add-widget' | translate }}"> |
286 | 286 | <md-tooltip md-direction="top"> |
... | ... | @@ -290,7 +290,7 @@ |
290 | 290 | </md-button> |
291 | 291 | </md-fab-trigger> |
292 | 292 | <md-fab-actions> |
293 | - <md-button ng-disabled="loading" | |
293 | + <md-button ng-disabled="$root.loading" | |
294 | 294 | class="tmd-accent md-hue-2 md-fab" ng-click="vm.addWidget($event)" |
295 | 295 | aria-label="{{ 'action.create' | translate }}"> |
296 | 296 | <md-tooltip md-direction="top"> |
... | ... | @@ -298,7 +298,7 @@ |
298 | 298 | </md-tooltip> |
299 | 299 | <ng-md-icon icon="insert_drive_file"></ng-md-icon> |
300 | 300 | </md-button> |
301 | - <md-button ng-disabled="loading" | |
301 | + <md-button ng-disabled="$root.loading" | |
302 | 302 | class="tmd-accent md-hue-2 md-fab" ng-click="vm.importWidget($event)" |
303 | 303 | aria-label="{{ 'action.import' | translate }}"> |
304 | 304 | <md-tooltip md-direction="top"> |
... | ... | @@ -308,7 +308,7 @@ |
308 | 308 | </md-button> |
309 | 309 | </md-fab-actions> |
310 | 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 | 312 | class="tb-btn-footer md-accent md-hue-2 md-fab" |
313 | 313 | aria-label="{{ 'action.apply' | translate }}" |
314 | 314 | ng-click="vm.saveDashboard()"> |
... | ... | @@ -317,8 +317,8 @@ |
317 | 317 | </md-tooltip> |
318 | 318 | <ng-md-icon icon="done"></ng-md-icon> |
319 | 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 | 322 | class="tb-btn-footer md-accent md-hue-2 md-fab" |
323 | 323 | aria-label="{{ 'action.edit-mode' | translate }}" |
324 | 324 | ng-click="vm.toggleDashboardEditMode()"> | ... | ... |
... | ... | @@ -75,7 +75,7 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid |
75 | 75 | function success(aliasInfo) { |
76 | 76 | var entity = aliasInfo.currentEntity; |
77 | 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 | 79 | function success(keys) { |
80 | 80 | deferred.resolve(keys); |
81 | 81 | }, | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | 'background-attachment': 'scroll', |
23 | 23 | 'background-size': vm.layoutCtx.gridSettings.backgroundSizeMode || '100%', |
24 | 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 | 26 | ng-style="{'color': vm.layoutCtx.gridSettings.color}" |
27 | 27 | style="text-transform: uppercase; display: flex; z-index: 1; pointer-events: none;" |
28 | 28 | class="md-headline tb-absolute-fill"> | ... | ... |
... | ... | @@ -26,11 +26,11 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading"> | |
33 | + <fieldset ng-disabled="$root.loading"> | |
34 | 34 | <div layout="row" layout-align="start center"> |
35 | 35 | <md-checkbox ng-disabled="true" flex aria-label="{{ 'layout.main' | translate }}" |
36 | 36 | ng-model="vm.displayLayouts.main">{{ 'layout.main' | translate }} |
... | ... | @@ -56,10 +56,10 @@ |
56 | 56 | </md-dialog-content> |
57 | 57 | <md-dialog-actions layout="row"> |
58 | 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 | 60 | {{ 'action.save' | translate }} |
61 | 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 | 63 | </md-dialog-actions> |
64 | 64 | </form> |
65 | 65 | </md-dialog> | ... | ... |
... | ... | @@ -26,11 +26,11 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading"> | |
33 | + <fieldset ng-disabled="$root.loading"> | |
34 | 34 | <div layout="row" layout-align="start center"> |
35 | 35 | <md-button flex class="tb-layout-button md-raised md-primary" layout="column" |
36 | 36 | ng-click="vm.selectLayout($event, 'main')"> | ... | ... |
... | ... | @@ -26,12 +26,12 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <md-content class="md-padding" layout="column"> |
34 | - <fieldset ng-disabled="loading"> | |
34 | + <fieldset ng-disabled="$root.loading"> | |
35 | 35 | <md-input-container class="md-block"> |
36 | 36 | <label translate>dashboard.state-name</label> |
37 | 37 | <input name="name" required ng-model="vm.state.name"> |
... | ... | @@ -57,11 +57,11 @@ |
57 | 57 | </md-dialog-content> |
58 | 58 | <md-dialog-actions layout="row"> |
59 | 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 | 61 | class="md-raised md-primary"> |
62 | 62 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} |
63 | 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 | 65 | {{ 'action.cancel' | translate }} |
66 | 66 | </md-button> |
67 | 67 | </md-dialog-actions> | ... | ... |
... | ... | @@ -26,11 +26,11 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading"> | |
33 | + <fieldset ng-disabled="$root.loading"> | |
34 | 34 | <div class="manage-dashboard-states" layout="column"> |
35 | 35 | <md-toolbar class="md-table-toolbar md-default" ng-show="vm.query.search === null"> |
36 | 36 | <div class="md-toolbar-tools"> |
... | ... | @@ -118,10 +118,10 @@ |
118 | 118 | </md-dialog-content> |
119 | 119 | <md-dialog-actions layout="row"> |
120 | 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 | 122 | {{ 'action.save' | translate }} |
123 | 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 | 125 | </md-dialog-actions> |
126 | 126 | </form> |
127 | 127 | </md-dialog> | ... | ... |
... | ... | @@ -26,11 +26,11 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading"> | |
33 | + <fieldset ng-disabled="$root.loading"> | |
34 | 34 | <md-select required aria-label="{{ 'dashboard.state' | translate }}" ng-model="vm.stateId"> |
35 | 35 | <md-option ng-repeat="(stateId, state) in vm.states" ng-value="stateId"> |
36 | 36 | {{state.name}} |
... | ... | @@ -41,10 +41,10 @@ |
41 | 41 | </md-dialog-content> |
42 | 42 | <md-dialog-actions layout="row"> |
43 | 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 | 45 | {{ 'action.save' | translate }} |
46 | 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 | 48 | </md-dialog-actions> |
49 | 49 | </form> |
50 | 50 | </md-dialog> | ... | ... |
... | ... | @@ -27,8 +27,8 @@ |
27 | 27 | </md-button> |
28 | 28 | </div> |
29 | 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 | 32 | <md-dialog-content> |
33 | 33 | <div class="md-dialog-content"> |
34 | 34 | <tb-device device="vm.item" is-edit="true" the-form="theForm"></tb-device> |
... | ... | @@ -36,10 +36,10 @@ |
36 | 36 | </md-dialog-content> |
37 | 37 | <md-dialog-actions layout="row"> |
38 | 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 | 40 | {{ 'action.add' | translate }} |
41 | 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 | 43 | </md-dialog-actions> |
44 | 44 | </form> |
45 | 45 | </md-dialog> |
\ No newline at end of file | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset> |
... | ... | @@ -65,11 +65,11 @@ |
65 | 65 | </md-dialog-content> |
66 | 66 | <md-dialog-actions layout="row"> |
67 | 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 | 69 | class="md-raised md-primary"> |
70 | 70 | {{ 'action.assign' | translate }} |
71 | 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 | 73 | translate }} |
74 | 74 | </md-button> |
75 | 75 | </md-dialog-actions> | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset> |
... | ... | @@ -65,10 +65,10 @@ |
65 | 65 | </md-dialog-content> |
66 | 66 | <md-dialog-actions layout="row"> |
67 | 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 | 69 | {{ 'action.assign' | translate }} |
70 | 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 | 72 | translate }} |
73 | 73 | </md-button> |
74 | 74 | </md-dialog-actions> | ... | ... |
... | ... | @@ -26,14 +26,14 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading || vm.isReadOnly"> | |
33 | + <fieldset ng-disabled="$root.loading || vm.isReadOnly"> | |
34 | 34 | <md-input-container class="md-block"> |
35 | 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 | 37 | ng-change="vm.clear()"> |
38 | 38 | <md-option ng-repeat="credentialsType in vm.credentialsTypes" value="{{credentialsType.value}}"> |
39 | 39 | {{credentialsType.name}} |
... | ... | @@ -62,10 +62,10 @@ |
62 | 62 | </md-dialog-content> |
63 | 63 | <md-dialog-actions layout="row"> |
64 | 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 | 66 | {{ 'action.save' | translate }} |
67 | 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 | 69 | </md-dialog-actions> |
70 | 70 | </form> |
71 | 71 | </md-dialog> |
\ No newline at end of file | ... | ... |
... | ... | @@ -58,7 +58,7 @@ |
58 | 58 | ng-show="!isEdit && isPublic && (deviceScope === 'customer' || deviceScope === 'tenant')"> |
59 | 59 | {{ 'device.device-public' | translate }} |
60 | 60 | </div> |
61 | - <fieldset ng-disabled="loading || !isEdit"> | |
61 | + <fieldset ng-disabled="$root.loading || !isEdit"> | |
62 | 62 | <md-input-container class="md-block"> |
63 | 63 | <label translate>device.name</label> |
64 | 64 | <input required name="name" ng-model="device.name"> |
... | ... | @@ -67,14 +67,14 @@ |
67 | 67 | </div> |
68 | 68 | </md-input-container> |
69 | 69 | <tb-entity-subtype-autocomplete |
70 | - ng-disabled="loading || !isEdit" | |
70 | + ng-disabled="$root.loading || !isEdit" | |
71 | 71 | tb-required="true" |
72 | 72 | the-form="theForm" |
73 | 73 | ng-model="device.type" |
74 | 74 | entity-type="types.entityType.device"> |
75 | 75 | </tb-entity-subtype-autocomplete> |
76 | 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 | 78 | ng-model="device.additionalInfo.gateway">{{ 'device.is-gateway' | translate }} |
79 | 79 | </md-checkbox> |
80 | 80 | </md-input-container> | ... | ... |
... | ... | @@ -26,11 +26,11 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading"> | |
33 | + <fieldset ng-disabled="$root.loading"> | |
34 | 34 | <div flex layout="column"> |
35 | 35 | <div layout="row"> |
36 | 36 | <md-input-container flex class="md-block"> |
... | ... | @@ -64,10 +64,10 @@ |
64 | 64 | </md-dialog-content> |
65 | 65 | <md-dialog-actions layout="row"> |
66 | 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 | 68 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} |
69 | 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 | 71 | </md-dialog-actions> |
72 | 72 | </form> |
73 | 73 | </md-dialog> | ... | ... |
... | ... | @@ -26,8 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <div class="tb-aliases-header" flex layout="row" layout-align="start center"> |
32 | 32 | <span flex="5"></span> |
33 | 33 | <div flex layout="row" layout-align="start center"> |
... | ... | @@ -40,7 +40,7 @@ |
40 | 40 | <md-divider></md-divider> |
41 | 41 | <md-dialog-content> |
42 | 42 | <div class="md-dialog-content"> |
43 | - <fieldset ng-disabled="loading"> | |
43 | + <fieldset ng-disabled="$root.loading"> | |
44 | 44 | <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index"> |
45 | 45 | <span flex="5">{{$index + 1}}.</span> |
46 | 46 | <di class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center"> |
... | ... | @@ -63,7 +63,7 @@ |
63 | 63 | aria-label="resolve-multiple-switcher"> |
64 | 64 | </md-switch> |
65 | 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 | 67 | ng-click="vm.editAlias($event, entityAlias)" aria-label="{{ 'action.edit' | translate }}"> |
68 | 68 | <md-tooltip md-direction="top"> |
69 | 69 | {{ 'alias.edit' | translate }} |
... | ... | @@ -72,7 +72,7 @@ |
72 | 72 | edit |
73 | 73 | </md-icon> |
74 | 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 | 76 | ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}"> |
77 | 77 | <md-tooltip md-direction="top"> |
78 | 78 | {{ 'entity.remove-alias' | translate }} |
... | ... | @@ -87,7 +87,7 @@ |
87 | 87 | </div> |
88 | 88 | </md-dialog-content> |
89 | 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 | 91 | ng-click="vm.addAlias($event)" |
92 | 92 | aria-label="{{ 'alias.add' | translate }}"> |
93 | 93 | <md-tooltip md-direction="top"> |
... | ... | @@ -96,10 +96,10 @@ |
96 | 96 | <span translate>alias.add</span> |
97 | 97 | </md-button> |
98 | 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 | 100 | {{ 'action.save' | translate }} |
101 | 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 | 103 | </md-dialog-actions> |
104 | 104 | </form> |
105 | 105 | </md-dialog> |
\ No newline at end of file | ... | ... |
... | ... | @@ -26,12 +26,12 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <md-content class="md-padding" layout="column"> |
34 | - <fieldset ng-disabled="loading"> | |
34 | + <fieldset ng-disabled="$root.loading"> | |
35 | 35 | <md-input-container class="md-block"> |
36 | 36 | <label translate>attribute.key</label> |
37 | 37 | <input required name="key" ng-model="vm.attribute.key"> |
... | ... | @@ -42,7 +42,7 @@ |
42 | 42 | <section layout="row"> |
43 | 43 | <md-input-container flex="40" class="md-block" style="width: 200px;"> |
44 | 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 | 46 | <md-option ng-repeat="type in vm.valueTypes" ng-value="type"> |
47 | 47 | <md-icon md-svg-icon="{{ type.icon }}"></md-icon> |
48 | 48 | <span>{{type.name | translate}}</span> |
... | ... | @@ -83,11 +83,11 @@ |
83 | 83 | </md-dialog-content> |
84 | 84 | <md-dialog-actions layout="row"> |
85 | 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 | 87 | class="md-raised md-primary"> |
88 | 88 | {{ 'action.add' | translate }} |
89 | 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 | 91 | translate }} |
92 | 92 | </md-button> |
93 | 93 | </md-dialog-actions> | ... | ... |
... | ... | @@ -26,18 +26,18 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <md-content class="md-padding" layout="column"> |
34 | - <fieldset ng-disabled="loading"> | |
34 | + <fieldset ng-disabled="$root.loading"> | |
35 | 35 | <md-radio-group ng-model="vm.addToDashboardType" class="md-primary"> |
36 | 36 | <md-radio-button flex ng-value=0 class="md-primary md-align-top-left md-radio-interactive"> |
37 | 37 | <section flex layout="column" style="width: 300px;"> |
38 | 38 | <span translate style="padding-bottom: 10px;">dashboard.select-existing</span> |
39 | 39 | <tb-dashboard-autocomplete the-form="theForm" |
40 | - ng-disabled="loading || vm.addToDashboardType != 0" | |
40 | + ng-disabled="$root.loading || vm.addToDashboardType != 0" | |
41 | 41 | tb-required="vm.addToDashboardType === 0" |
42 | 42 | ng-model="vm.dashboardId" |
43 | 43 | select-first-dashboard="false"> |
... | ... | @@ -69,11 +69,11 @@ |
69 | 69 | style="margin-bottom: 0px; padding-right: 20px;"> |
70 | 70 | {{ 'dashboard.open-dashboard' | translate }} |
71 | 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 | 73 | class="md-raised md-primary"> |
74 | 74 | {{ 'action.add' | translate }} |
75 | 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 | 77 | translate }} |
78 | 78 | </md-button> |
79 | 79 | </md-dialog-actions> | ... | ... |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | <section ng-show="!disableAttributeScopeSelection"> |
20 | 20 | <md-input-container class="md-block" style="width: 200px;"> |
21 | 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 | 23 | <md-option ng-repeat="scope in attributeScopes" ng-value="scope"> |
24 | 24 | {{scope.name | translate}} |
25 | 25 | </md-option> | ... | ... |
... | ... | @@ -38,7 +38,7 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter |
38 | 38 | if (scope.excludeEntityIds && scope.excludeEntityIds.length) { |
39 | 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 | 42 | if (result) { |
43 | 43 | if (scope.excludeEntityIds && scope.excludeEntityIds.length) { |
44 | 44 | var entities = []; | ... | ... |
... | ... | @@ -38,7 +38,7 @@ export default function EntityListDirective($compile, $templateCache, $q, $mdUti |
38 | 38 | |
39 | 39 | scope.fetchEntities = function(searchText, limit) { |
40 | 40 | var deferred = $q.defer(); |
41 | - entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then( | |
41 | + entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit, {ignoreLoading: true}).then( | |
42 | 42 | function success(result) { |
43 | 43 | if (result) { |
44 | 44 | deferred.resolve(result); | ... | ... |
... | ... | @@ -93,9 +93,9 @@ export default function EntitySubtypeAutocomplete($compile, $templateCache, $q, |
93 | 93 | if (!scope.entitySubtypes) { |
94 | 94 | var entitySubtypesPromise; |
95 | 95 | if (scope.entityType == types.entityType.asset) { |
96 | - entitySubtypesPromise = assetService.getAssetTypes(); | |
96 | + entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true}); | |
97 | 97 | } else if (scope.entityType == types.entityType.device) { |
98 | - entitySubtypesPromise = deviceService.getDeviceTypes(); | |
98 | + entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true}); | |
99 | 99 | } |
100 | 100 | if (entitySubtypesPromise) { |
101 | 101 | entitySubtypesPromise.then( | ... | ... |
... | ... | @@ -95,9 +95,9 @@ export default function EntitySubtypeListDirective($compile, $templateCache, $q, |
95 | 95 | if (!scope.entitySubtypes) { |
96 | 96 | var entitySubtypesPromise; |
97 | 97 | if (scope.entityType == types.entityType.asset) { |
98 | - entitySubtypesPromise = assetService.getAssetTypes(); | |
98 | + entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true}); | |
99 | 99 | } else if (scope.entityType == types.entityType.device) { |
100 | - entitySubtypesPromise = deviceService.getDeviceTypes(); | |
100 | + entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true}); | |
101 | 101 | } |
102 | 102 | if (entitySubtypesPromise) { |
103 | 103 | entitySubtypesPromise.then( | ... | ... |
... | ... | @@ -73,9 +73,9 @@ export default function EntitySubtypeSelect($compile, $templateCache, $translate |
73 | 73 | scope.entitySubtypes = []; |
74 | 74 | var entitySubtypesPromise; |
75 | 75 | if (scope.entityType == types.entityType.asset) { |
76 | - entitySubtypesPromise = assetService.getAssetTypes(); | |
76 | + entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true}); | |
77 | 77 | } else if (scope.entityType == types.entityType.device) { |
78 | - entitySubtypesPromise = deviceService.getDeviceTypes(); | |
78 | + entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true}); | |
79 | 79 | } |
80 | 80 | if (entitySubtypesPromise) { |
81 | 81 | entitySubtypesPromise.then( | ... | ... |
... | ... | @@ -26,16 +26,16 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <md-content class="md-padding" layout="column"> |
34 | - <fieldset ng-disabled="loading"> | |
34 | + <fieldset ng-disabled="$root.loading"> | |
35 | 35 | <tb-relation-type-autocomplete ng-disabled="!vm.isAdd" |
36 | 36 | ng-model="vm.relation.type" |
37 | 37 | tb-required="true" |
38 | - ng-disabled="loading"> | |
38 | + ng-disabled="$root.loading"> | |
39 | 39 | </tb-relation-type-autocomplete> |
40 | 40 | <small>{{(vm.direction == vm.types.entitySearchDirection.from ? |
41 | 41 | 'relation.to-entity' : 'relation.from-entity') | translate}}</small> |
... | ... | @@ -61,11 +61,11 @@ |
61 | 61 | </md-dialog-content> |
62 | 62 | <md-dialog-actions layout="row"> |
63 | 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 | 65 | class="md-raised md-primary"> |
66 | 66 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} |
67 | 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 | 69 | translate }} |
70 | 70 | </md-button> |
71 | 71 | </md-dialog-actions> | ... | ... |
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | allowed-entity-types="allowedEntityTypes" |
38 | 38 | tb-required="false"> |
39 | 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 | 41 | ng-click="removeFilter($event, filter)" aria-label="{{ 'action.remove' | translate }}"> |
42 | 42 | <md-tooltip md-direction="top"> |
43 | 43 | {{ 'relation.remove-relation-filter' | translate }} |
... | ... | @@ -54,7 +54,7 @@ |
54 | 54 | class="tb-prompt" translate>relation.any-relation</span> |
55 | 55 | </div> |
56 | 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 | 58 | <md-tooltip md-direction="top"> |
59 | 59 | {{ 'relation.add-relation-filter' | translate }} |
60 | 60 | </md-tooltip> | ... | ... |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | <section layout="row"> |
20 | 20 | <md-input-container class="md-block" style="width: 200px;"> |
21 | 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 | 23 | <md-option ng-repeat="direction in vm.types.entitySearchDirection" ng-value="direction"> |
24 | 24 | {{ ('relation.search-direction.' + direction) | translate}} |
25 | 25 | </md-option> | ... | ... |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | </md-dialog-content> |
36 | 36 | <md-dialog-actions layout="row"> |
37 | 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 | 39 | translate }} |
40 | 40 | </md-button> |
41 | 41 | </md-dialog-actions> | ... | ... |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | <section layout="row"> |
20 | 20 | <md-input-container class="md-block" style="width: 200px;"> |
21 | 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 | 23 | <md-option ng-repeat="type in eventTypes" ng-value="type.value"> |
24 | 24 | {{type.name | translate}} |
25 | 25 | </md-option> |
... | ... | @@ -30,8 +30,8 @@ |
30 | 30 | <md-list flex layout="column" class="md-whiteframe-z1 tb-event-table"> |
31 | 31 | <md-list class="tb-row tb-header" layout="row" tb-event-header event-type="{{eventType}}"> |
32 | 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 | 35 | <md-divider></md-divider> |
36 | 36 | <span translate layout-align="center center" |
37 | 37 | style="margin-top: 25px;" | ... | ... |
... | ... | @@ -27,14 +27,14 @@ |
27 | 27 | </div> |
28 | 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 | 34 | <md-dialog-content> |
35 | 35 | <div class="md-dialog-content"> |
36 | 36 | <md-content class="md-padding" layout="column"> |
37 | - <fieldset ng-disabled="loading"> | |
37 | + <fieldset ng-disabled="$root.loading"> | |
38 | 38 | <section flex layout="row"> |
39 | 39 | <md-input-container flex="60" class="md-block" md-is-error="theForm.extensionId.$touched && theForm.extensionId.$invalid"> |
40 | 40 | <label translate>extension.extension-id</label> |
... | ... | @@ -74,7 +74,7 @@ |
74 | 74 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} |
75 | 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 | 78 | </md-button> |
79 | 79 | </md-dialog-actions> |
80 | 80 | </form> | ... | ... |
... | ... | @@ -26,11 +26,11 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 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 | 31 | <md-dialog-content> |
32 | 32 | <div class="md-dialog-content"> |
33 | - <fieldset ng-disabled="loading"> | |
33 | + <fieldset ng-disabled="$root.loading"> | |
34 | 34 | <div layout="column" layout-padding> |
35 | 35 | <div class="tb-container"> |
36 | 36 | <label class="tb-label" translate>{{ vm.importFileLabel }}</label> |
... | ... | @@ -63,10 +63,10 @@ |
63 | 63 | </md-dialog-content> |
64 | 64 | <md-dialog-actions layout="row"> |
65 | 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 | 67 | {{ 'action.import' | translate }} |
68 | 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 | 70 | </md-dialog-actions> |
71 | 71 | </form> |
72 | 72 | </md-dialog> | ... | ... |
... | ... | @@ -76,7 +76,7 @@ |
76 | 76 | </tb-user-menu> |
77 | 77 | </div> |
78 | 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 | 81 | <div flex layout="column" id="toast-parent" style="position: relative;"> |
82 | 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 | 1213 | "remove-widget-title": "Are you sure you want to remove the widget '{{widgetTitle}}'?", |
1214 | 1214 | "remove-widget-text": "After the confirmation the widget and all related data will become unrecoverable.", |
1215 | 1215 | "timeseries": "Time series", |
1216 | + "search-data": "Search data", | |
1216 | 1217 | "latest-values": "Latest values", |
1217 | 1218 | "rpc": "Control widget", |
1218 | 1219 | "alarm": "Alarm widget", | ... | ... |
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | </md-card-title-text> |
24 | 24 | </md-card-title> |
25 | 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 | 27 | <md-card-content> |
28 | 28 | <form class="create-password-form" ng-submit="vm.createPassword()"> |
29 | 29 | <div layout="column" layout-padding="" id="toast-parent"> | ... | ... |
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | </md-card-title-text> |
24 | 24 | </md-card-title> |
25 | 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 | 27 | <md-card-content> |
28 | 28 | <form class="login-form" ng-submit="vm.login()"> |
29 | 29 | <div layout="column" layout-padding="" id="toast-parent"> | ... | ... |
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | </md-card-title-text> |
24 | 24 | </md-card-title> |
25 | 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 | 27 | <md-card-content> |
28 | 28 | <form class="request-password-reset-form" ng-submit="vm.sendResetPasswordLink()"> |
29 | 29 | <div layout="column" layout-padding="" id="toast-parent"> | ... | ... |