Commit 7a34e2a3f53f3e6bba87427e379ed66132bc7360
Merge branch 'master' of github.com:thingsboard/thingsboard
Showing
63 changed files
with
427 additions
and
306 deletions
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.springframework.beans.factory.annotation.Autowired; | ||
19 | import org.springframework.http.HttpStatus; | 20 | import org.springframework.http.HttpStatus; |
20 | import org.springframework.security.access.prepost.PreAuthorize; | 21 | import org.springframework.security.access.prepost.PreAuthorize; |
21 | import org.springframework.web.bind.annotation.*; | 22 | import org.springframework.web.bind.annotation.*; |
@@ -23,6 +24,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; | @@ -23,6 +24,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; | ||
23 | import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo; | 24 | import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo; |
24 | import org.thingsboard.server.common.data.oauth2.OAuth2ClientsParams; | 25 | import org.thingsboard.server.common.data.oauth2.OAuth2ClientsParams; |
25 | import org.thingsboard.server.common.data.oauth2.SchemeType; | 26 | import org.thingsboard.server.common.data.oauth2.SchemeType; |
27 | +import org.thingsboard.server.dao.oauth2.OAuth2Configuration; | ||
26 | import org.thingsboard.server.queue.util.TbCoreComponent; | 28 | import org.thingsboard.server.queue.util.TbCoreComponent; |
27 | import org.thingsboard.server.service.security.permission.Operation; | 29 | import org.thingsboard.server.service.security.permission.Operation; |
28 | import org.thingsboard.server.service.security.permission.Resource; | 30 | import org.thingsboard.server.service.security.permission.Resource; |
@@ -36,6 +38,10 @@ import java.util.List; | @@ -36,6 +38,10 @@ import java.util.List; | ||
36 | @RequestMapping("/api") | 38 | @RequestMapping("/api") |
37 | @Slf4j | 39 | @Slf4j |
38 | public class OAuth2Controller extends BaseController { | 40 | public class OAuth2Controller extends BaseController { |
41 | + | ||
42 | + @Autowired | ||
43 | + private OAuth2Configuration oAuth2Configuration; | ||
44 | + | ||
39 | @RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST) | 45 | @RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST) |
40 | @ResponseBody | 46 | @ResponseBody |
41 | public List<OAuth2ClientInfo> getOAuth2Clients(HttpServletRequest request) throws ThingsboardException { | 47 | public List<OAuth2ClientInfo> getOAuth2Clients(HttpServletRequest request) throws ThingsboardException { |
@@ -70,4 +76,16 @@ public class OAuth2Controller extends BaseController { | @@ -70,4 +76,16 @@ public class OAuth2Controller extends BaseController { | ||
70 | throw handleException(e); | 76 | throw handleException(e); |
71 | } | 77 | } |
72 | } | 78 | } |
79 | + | ||
80 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") | ||
81 | + @RequestMapping(value = "/oauth2/loginProcessingUrl", method = RequestMethod.GET) | ||
82 | + @ResponseBody | ||
83 | + public String getLoginProcessingUrl() throws ThingsboardException { | ||
84 | + try { | ||
85 | + accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.READ); | ||
86 | + return "\"" + oAuth2Configuration.getLoginProcessingUrl() + "\""; | ||
87 | + } catch (Exception e) { | ||
88 | + throw handleException(e); | ||
89 | + } | ||
90 | + } | ||
73 | } | 91 | } |
@@ -27,6 +27,6 @@ import java.util.Set; | @@ -27,6 +27,6 @@ import java.util.Set; | ||
27 | @NoArgsConstructor | 27 | @NoArgsConstructor |
28 | @AllArgsConstructor | 28 | @AllArgsConstructor |
29 | public class OAuth2ClientsDomainParams { | 29 | public class OAuth2ClientsDomainParams { |
30 | - private Set<DomainInfo> domainInfos; | ||
31 | - private Set<ClientRegistrationDto> clientRegistrations; | ||
32 | -} | ||
30 | + private List<DomainInfo> domainInfos; | ||
31 | + private List<ClientRegistrationDto> clientRegistrations; | ||
32 | +} |
@@ -16,6 +16,8 @@ | @@ -16,6 +16,8 @@ | ||
16 | package org.thingsboard.server.common.data.oauth2; | 16 | package org.thingsboard.server.common.data.oauth2; |
17 | 17 | ||
18 | import lombok.*; | 18 | import lombok.*; |
19 | + | ||
20 | +import java.util.List; | ||
19 | import java.util.Set; | 21 | import java.util.Set; |
20 | 22 | ||
21 | @EqualsAndHashCode | 23 | @EqualsAndHashCode |
@@ -26,5 +28,5 @@ import java.util.Set; | @@ -26,5 +28,5 @@ import java.util.Set; | ||
26 | @AllArgsConstructor | 28 | @AllArgsConstructor |
27 | public class OAuth2ClientsParams { | 29 | public class OAuth2ClientsParams { |
28 | private boolean enabled; | 30 | private boolean enabled; |
29 | - private Set<OAuth2ClientsDomainParams> domainsParams; | ||
30 | -} | ||
31 | + private List<OAuth2ClientsDomainParams> domainsParams; | ||
32 | +} |
@@ -32,19 +32,19 @@ public class OAuth2Utils { | @@ -32,19 +32,19 @@ public class OAuth2Utils { | ||
32 | } | 32 | } |
33 | 33 | ||
34 | public static OAuth2ClientsParams toOAuth2Params(List<ExtendedOAuth2ClientRegistrationInfo> extendedOAuth2ClientRegistrationInfos) { | 34 | public static OAuth2ClientsParams toOAuth2Params(List<ExtendedOAuth2ClientRegistrationInfo> extendedOAuth2ClientRegistrationInfos) { |
35 | - Map<OAuth2ClientRegistrationInfoId, Set<DomainInfo>> domainsByInfoId = new HashMap<>(); | ||
36 | - Map<OAuth2ClientRegistrationInfoId, OAuth2ClientRegistrationInfo> infoById = new HashMap<>(); | 35 | + Map<OAuth2ClientRegistrationInfoId, List<DomainInfo>> domainsByInfoId = new LinkedHashMap<>(); |
36 | + Map<OAuth2ClientRegistrationInfoId, OAuth2ClientRegistrationInfo> infoById = new LinkedHashMap<>(); | ||
37 | for (ExtendedOAuth2ClientRegistrationInfo extendedClientRegistrationInfo : extendedOAuth2ClientRegistrationInfos) { | 37 | for (ExtendedOAuth2ClientRegistrationInfo extendedClientRegistrationInfo : extendedOAuth2ClientRegistrationInfos) { |
38 | String domainName = extendedClientRegistrationInfo.getDomainName(); | 38 | String domainName = extendedClientRegistrationInfo.getDomainName(); |
39 | SchemeType domainScheme = extendedClientRegistrationInfo.getDomainScheme(); | 39 | SchemeType domainScheme = extendedClientRegistrationInfo.getDomainScheme(); |
40 | - domainsByInfoId.computeIfAbsent(extendedClientRegistrationInfo.getId(), key -> new HashSet<>()) | 40 | + domainsByInfoId.computeIfAbsent(extendedClientRegistrationInfo.getId(), key -> new ArrayList<>()) |
41 | .add(new DomainInfo(domainScheme, domainName)); | 41 | .add(new DomainInfo(domainScheme, domainName)); |
42 | infoById.put(extendedClientRegistrationInfo.getId(), extendedClientRegistrationInfo); | 42 | infoById.put(extendedClientRegistrationInfo.getId(), extendedClientRegistrationInfo); |
43 | } | 43 | } |
44 | - Map<Set<DomainInfo>, OAuth2ClientsDomainParams> domainParamsMap = new HashMap<>(); | 44 | + Map<List<DomainInfo>, OAuth2ClientsDomainParams> domainParamsMap = new LinkedHashMap<>(); |
45 | domainsByInfoId.forEach((clientRegistrationInfoId, domainInfos) -> { | 45 | domainsByInfoId.forEach((clientRegistrationInfoId, domainInfos) -> { |
46 | domainParamsMap.computeIfAbsent(domainInfos, | 46 | domainParamsMap.computeIfAbsent(domainInfos, |
47 | - key -> new OAuth2ClientsDomainParams(key, new HashSet<>()) | 47 | + key -> new OAuth2ClientsDomainParams(key, new ArrayList<>()) |
48 | ) | 48 | ) |
49 | .getClientRegistrations() | 49 | .getClientRegistrations() |
50 | .add(toClientRegistrationDto(infoById.get(clientRegistrationInfoId))); | 50 | .add(toClientRegistrationDto(infoById.get(clientRegistrationInfoId))); |
@@ -52,7 +52,7 @@ public class OAuth2Utils { | @@ -52,7 +52,7 @@ public class OAuth2Utils { | ||
52 | boolean enabled = extendedOAuth2ClientRegistrationInfos.stream() | 52 | boolean enabled = extendedOAuth2ClientRegistrationInfos.stream() |
53 | .map(OAuth2ClientRegistrationInfo::isEnabled) | 53 | .map(OAuth2ClientRegistrationInfo::isEnabled) |
54 | .findFirst().orElse(false); | 54 | .findFirst().orElse(false); |
55 | - return new OAuth2ClientsParams(enabled, new HashSet<>(domainParamsMap.values())); | 55 | + return new OAuth2ClientsParams(enabled, new ArrayList<>(domainParamsMap.values())); |
56 | } | 56 | } |
57 | 57 | ||
58 | public static ClientRegistrationDto toClientRegistrationDto(OAuth2ClientRegistrationInfo oAuth2ClientRegistrationInfo) { | 58 | public static ClientRegistrationDto toClientRegistrationDto(OAuth2ClientRegistrationInfo oAuth2ClientRegistrationInfo) { |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.dao.service; | 16 | package org.thingsboard.server.dao.service; |
17 | 17 | ||
18 | +import com.google.common.collect.Lists; | ||
18 | import com.google.common.collect.Sets; | 19 | import com.google.common.collect.Sets; |
19 | import org.junit.After; | 20 | import org.junit.After; |
20 | import org.junit.Assert; | 21 | import org.junit.Assert; |
@@ -29,7 +30,7 @@ import java.util.*; | @@ -29,7 +30,7 @@ import java.util.*; | ||
29 | import java.util.stream.Collectors; | 30 | import java.util.stream.Collectors; |
30 | 31 | ||
31 | public class BaseOAuth2ServiceTest extends AbstractServiceTest { | 32 | public class BaseOAuth2ServiceTest extends AbstractServiceTest { |
32 | - private static final OAuth2ClientsParams EMPTY_PARAMS = new OAuth2ClientsParams(false, new HashSet<>()); | 33 | + private static final OAuth2ClientsParams EMPTY_PARAMS = new OAuth2ClientsParams(false, new ArrayList<>()); |
33 | 34 | ||
34 | @Autowired | 35 | @Autowired |
35 | protected OAuth2Service oAuth2Service; | 36 | protected OAuth2Service oAuth2Service; |
@@ -48,14 +49,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -48,14 +49,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
48 | 49 | ||
49 | @Test(expected = DataValidationException.class) | 50 | @Test(expected = DataValidationException.class) |
50 | public void testSaveHttpAndMixedDomainsTogether() { | 51 | public void testSaveHttpAndMixedDomainsTogether() { |
51 | - OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 52 | + OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
52 | OAuth2ClientsDomainParams.builder() | 53 | OAuth2ClientsDomainParams.builder() |
53 | - .domainInfos(Sets.newHashSet( | 54 | + .domainInfos(Lists.newArrayList( |
54 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), | 55 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), |
55 | DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(), | 56 | DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(), |
56 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() | 57 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() |
57 | )) | 58 | )) |
58 | - .clientRegistrations(Sets.newHashSet( | 59 | + .clientRegistrations(Lists.newArrayList( |
59 | validClientRegistrationDto(), | 60 | validClientRegistrationDto(), |
60 | validClientRegistrationDto(), | 61 | validClientRegistrationDto(), |
61 | validClientRegistrationDto() | 62 | validClientRegistrationDto() |
@@ -67,14 +68,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -67,14 +68,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
67 | 68 | ||
68 | @Test(expected = DataValidationException.class) | 69 | @Test(expected = DataValidationException.class) |
69 | public void testSaveHttpsAndMixedDomainsTogether() { | 70 | public void testSaveHttpsAndMixedDomainsTogether() { |
70 | - OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 71 | + OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
71 | OAuth2ClientsDomainParams.builder() | 72 | OAuth2ClientsDomainParams.builder() |
72 | - .domainInfos(Sets.newHashSet( | 73 | + .domainInfos(Lists.newArrayList( |
73 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build(), | 74 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build(), |
74 | DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(), | 75 | DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(), |
75 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() | 76 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() |
76 | )) | 77 | )) |
77 | - .clientRegistrations(Sets.newHashSet( | 78 | + .clientRegistrations(Lists.newArrayList( |
78 | validClientRegistrationDto(), | 79 | validClientRegistrationDto(), |
79 | validClientRegistrationDto(), | 80 | validClientRegistrationDto(), |
80 | validClientRegistrationDto() | 81 | validClientRegistrationDto() |
@@ -131,20 +132,20 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -131,20 +132,20 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
131 | Assert.assertNotNull(foundClientsParams); | 132 | Assert.assertNotNull(foundClientsParams); |
132 | Assert.assertEquals(clientsParams, foundClientsParams); | 133 | Assert.assertEquals(clientsParams, foundClientsParams); |
133 | 134 | ||
134 | - OAuth2ClientsParams newClientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 135 | + OAuth2ClientsParams newClientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
135 | OAuth2ClientsDomainParams.builder() | 136 | OAuth2ClientsDomainParams.builder() |
136 | - .domainInfos(Sets.newHashSet( | 137 | + .domainInfos(Lists.newArrayList( |
137 | DomainInfo.builder().name("another-domain").scheme(SchemeType.HTTPS).build() | 138 | DomainInfo.builder().name("another-domain").scheme(SchemeType.HTTPS).build() |
138 | )) | 139 | )) |
139 | - .clientRegistrations(Sets.newHashSet( | 140 | + .clientRegistrations(Lists.newArrayList( |
140 | validClientRegistrationDto() | 141 | validClientRegistrationDto() |
141 | )) | 142 | )) |
142 | .build(), | 143 | .build(), |
143 | OAuth2ClientsDomainParams.builder() | 144 | OAuth2ClientsDomainParams.builder() |
144 | - .domainInfos(Sets.newHashSet( | 145 | + .domainInfos(Lists.newArrayList( |
145 | DomainInfo.builder().name("test-domain").scheme(SchemeType.MIXED).build() | 146 | DomainInfo.builder().name("test-domain").scheme(SchemeType.MIXED).build() |
146 | )) | 147 | )) |
147 | - .clientRegistrations(Sets.newHashSet( | 148 | + .clientRegistrations(Lists.newArrayList( |
148 | validClientRegistrationDto() | 149 | validClientRegistrationDto() |
149 | )) | 150 | )) |
150 | .build() | 151 | .build() |
@@ -157,22 +158,22 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -157,22 +158,22 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
157 | 158 | ||
158 | @Test | 159 | @Test |
159 | public void testGetOAuth2Clients() { | 160 | public void testGetOAuth2Clients() { |
160 | - Set<ClientRegistrationDto> firstGroup = Sets.newHashSet( | 161 | + List<ClientRegistrationDto> firstGroup = Lists.newArrayList( |
161 | validClientRegistrationDto(), | 162 | validClientRegistrationDto(), |
162 | validClientRegistrationDto(), | 163 | validClientRegistrationDto(), |
163 | validClientRegistrationDto(), | 164 | validClientRegistrationDto(), |
164 | validClientRegistrationDto() | 165 | validClientRegistrationDto() |
165 | ); | 166 | ); |
166 | - Set<ClientRegistrationDto> secondGroup = Sets.newHashSet( | 167 | + List<ClientRegistrationDto> secondGroup = Lists.newArrayList( |
167 | validClientRegistrationDto(), | 168 | validClientRegistrationDto(), |
168 | validClientRegistrationDto() | 169 | validClientRegistrationDto() |
169 | ); | 170 | ); |
170 | - Set<ClientRegistrationDto> thirdGroup = Sets.newHashSet( | 171 | + List<ClientRegistrationDto> thirdGroup = Lists.newArrayList( |
171 | validClientRegistrationDto() | 172 | validClientRegistrationDto() |
172 | ); | 173 | ); |
173 | - OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 174 | + OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
174 | OAuth2ClientsDomainParams.builder() | 175 | OAuth2ClientsDomainParams.builder() |
175 | - .domainInfos(Sets.newHashSet( | 176 | + .domainInfos(Lists.newArrayList( |
176 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), | 177 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), |
177 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), | 178 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), |
178 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() | 179 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() |
@@ -180,14 +181,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -180,14 +181,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
180 | .clientRegistrations(firstGroup) | 181 | .clientRegistrations(firstGroup) |
181 | .build(), | 182 | .build(), |
182 | OAuth2ClientsDomainParams.builder() | 183 | OAuth2ClientsDomainParams.builder() |
183 | - .domainInfos(Sets.newHashSet( | 184 | + .domainInfos(Lists.newArrayList( |
184 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), | 185 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), |
185 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() | 186 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() |
186 | )) | 187 | )) |
187 | .clientRegistrations(secondGroup) | 188 | .clientRegistrations(secondGroup) |
188 | .build(), | 189 | .build(), |
189 | OAuth2ClientsDomainParams.builder() | 190 | OAuth2ClientsDomainParams.builder() |
190 | - .domainInfos(Sets.newHashSet( | 191 | + .domainInfos(Lists.newArrayList( |
191 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(), | 192 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(), |
192 | DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build() | 193 | DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build() |
193 | )) | 194 | )) |
@@ -285,15 +286,15 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -285,15 +286,15 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
285 | 286 | ||
286 | @Test | 287 | @Test |
287 | public void testGetOAuth2ClientsForHttpAndHttps() { | 288 | public void testGetOAuth2ClientsForHttpAndHttps() { |
288 | - Set<ClientRegistrationDto> firstGroup = Sets.newHashSet( | 289 | + List<ClientRegistrationDto> firstGroup = Lists.newArrayList( |
289 | validClientRegistrationDto(), | 290 | validClientRegistrationDto(), |
290 | validClientRegistrationDto(), | 291 | validClientRegistrationDto(), |
291 | validClientRegistrationDto(), | 292 | validClientRegistrationDto(), |
292 | validClientRegistrationDto() | 293 | validClientRegistrationDto() |
293 | ); | 294 | ); |
294 | - OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 295 | + OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
295 | OAuth2ClientsDomainParams.builder() | 296 | OAuth2ClientsDomainParams.builder() |
296 | - .domainInfos(Sets.newHashSet( | 297 | + .domainInfos(Lists.newArrayList( |
297 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), | 298 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), |
298 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), | 299 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), |
299 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build() | 300 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build() |
@@ -335,25 +336,25 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -335,25 +336,25 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
335 | 336 | ||
336 | @Test | 337 | @Test |
337 | public void testGetDisabledOAuth2Clients() { | 338 | public void testGetDisabledOAuth2Clients() { |
338 | - OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 339 | + OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
339 | OAuth2ClientsDomainParams.builder() | 340 | OAuth2ClientsDomainParams.builder() |
340 | - .domainInfos(Sets.newHashSet( | 341 | + .domainInfos(Lists.newArrayList( |
341 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), | 342 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), |
342 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), | 343 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), |
343 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() | 344 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() |
344 | )) | 345 | )) |
345 | - .clientRegistrations(Sets.newHashSet( | 346 | + .clientRegistrations(Lists.newArrayList( |
346 | validClientRegistrationDto(), | 347 | validClientRegistrationDto(), |
347 | validClientRegistrationDto(), | 348 | validClientRegistrationDto(), |
348 | validClientRegistrationDto() | 349 | validClientRegistrationDto() |
349 | )) | 350 | )) |
350 | .build(), | 351 | .build(), |
351 | OAuth2ClientsDomainParams.builder() | 352 | OAuth2ClientsDomainParams.builder() |
352 | - .domainInfos(Sets.newHashSet( | 353 | + .domainInfos(Lists.newArrayList( |
353 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), | 354 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), |
354 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() | 355 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() |
355 | )) | 356 | )) |
356 | - .clientRegistrations(Sets.newHashSet( | 357 | + .clientRegistrations(Lists.newArrayList( |
357 | validClientRegistrationDto(), | 358 | validClientRegistrationDto(), |
358 | validClientRegistrationDto() | 359 | validClientRegistrationDto() |
359 | )) | 360 | )) |
@@ -374,35 +375,35 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -374,35 +375,35 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
374 | 375 | ||
375 | @Test | 376 | @Test |
376 | public void testFindAllClientRegistrationInfos() { | 377 | public void testFindAllClientRegistrationInfos() { |
377 | - OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 378 | + OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
378 | OAuth2ClientsDomainParams.builder() | 379 | OAuth2ClientsDomainParams.builder() |
379 | - .domainInfos(Sets.newHashSet( | 380 | + .domainInfos(Lists.newArrayList( |
380 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), | 381 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), |
381 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), | 382 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), |
382 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() | 383 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() |
383 | )) | 384 | )) |
384 | - .clientRegistrations(Sets.newHashSet( | 385 | + .clientRegistrations(Lists.newArrayList( |
385 | validClientRegistrationDto(), | 386 | validClientRegistrationDto(), |
386 | validClientRegistrationDto(), | 387 | validClientRegistrationDto(), |
387 | validClientRegistrationDto() | 388 | validClientRegistrationDto() |
388 | )) | 389 | )) |
389 | .build(), | 390 | .build(), |
390 | OAuth2ClientsDomainParams.builder() | 391 | OAuth2ClientsDomainParams.builder() |
391 | - .domainInfos(Sets.newHashSet( | 392 | + .domainInfos(Lists.newArrayList( |
392 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), | 393 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), |
393 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() | 394 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() |
394 | )) | 395 | )) |
395 | - .clientRegistrations(Sets.newHashSet( | 396 | + .clientRegistrations(Lists.newArrayList( |
396 | validClientRegistrationDto(), | 397 | validClientRegistrationDto(), |
397 | validClientRegistrationDto() | 398 | validClientRegistrationDto() |
398 | )) | 399 | )) |
399 | .build(), | 400 | .build(), |
400 | OAuth2ClientsDomainParams.builder() | 401 | OAuth2ClientsDomainParams.builder() |
401 | - .domainInfos(Sets.newHashSet( | 402 | + .domainInfos(Lists.newArrayList( |
402 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(), | 403 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(), |
403 | DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build() | 404 | DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build() |
404 | )) | 405 | )) |
405 | - .clientRegistrations(Sets.newHashSet( | 406 | + .clientRegistrations(Lists.newArrayList( |
406 | validClientRegistrationDto() | 407 | validClientRegistrationDto() |
407 | )) | 408 | )) |
408 | .build() | 409 | .build() |
@@ -423,35 +424,35 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -423,35 +424,35 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
423 | 424 | ||
424 | @Test | 425 | @Test |
425 | public void testFindClientRegistrationById() { | 426 | public void testFindClientRegistrationById() { |
426 | - OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Sets.newHashSet( | 427 | + OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList( |
427 | OAuth2ClientsDomainParams.builder() | 428 | OAuth2ClientsDomainParams.builder() |
428 | - .domainInfos(Sets.newHashSet( | 429 | + .domainInfos(Lists.newArrayList( |
429 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), | 430 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), |
430 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), | 431 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), |
431 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() | 432 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() |
432 | )) | 433 | )) |
433 | - .clientRegistrations(Sets.newHashSet( | 434 | + .clientRegistrations(Lists.newArrayList( |
434 | validClientRegistrationDto(), | 435 | validClientRegistrationDto(), |
435 | validClientRegistrationDto(), | 436 | validClientRegistrationDto(), |
436 | validClientRegistrationDto() | 437 | validClientRegistrationDto() |
437 | )) | 438 | )) |
438 | .build(), | 439 | .build(), |
439 | OAuth2ClientsDomainParams.builder() | 440 | OAuth2ClientsDomainParams.builder() |
440 | - .domainInfos(Sets.newHashSet( | 441 | + .domainInfos(Lists.newArrayList( |
441 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), | 442 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(), |
442 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() | 443 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() |
443 | )) | 444 | )) |
444 | - .clientRegistrations(Sets.newHashSet( | 445 | + .clientRegistrations(Lists.newArrayList( |
445 | validClientRegistrationDto(), | 446 | validClientRegistrationDto(), |
446 | validClientRegistrationDto() | 447 | validClientRegistrationDto() |
447 | )) | 448 | )) |
448 | .build(), | 449 | .build(), |
449 | OAuth2ClientsDomainParams.builder() | 450 | OAuth2ClientsDomainParams.builder() |
450 | - .domainInfos(Sets.newHashSet( | 451 | + .domainInfos(Lists.newArrayList( |
451 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(), | 452 | DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(), |
452 | DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build() | 453 | DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build() |
453 | )) | 454 | )) |
454 | - .clientRegistrations(Sets.newHashSet( | 455 | + .clientRegistrations(Lists.newArrayList( |
455 | validClientRegistrationDto() | 456 | validClientRegistrationDto() |
456 | )) | 457 | )) |
457 | .build() | 458 | .build() |
@@ -466,14 +467,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -466,14 +467,14 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
466 | } | 467 | } |
467 | 468 | ||
468 | private OAuth2ClientsParams createDefaultClientsParams() { | 469 | private OAuth2ClientsParams createDefaultClientsParams() { |
469 | - return new OAuth2ClientsParams(true, Sets.newHashSet( | 470 | + return new OAuth2ClientsParams(true, Lists.newArrayList( |
470 | OAuth2ClientsDomainParams.builder() | 471 | OAuth2ClientsDomainParams.builder() |
471 | - .domainInfos(Sets.newHashSet( | 472 | + .domainInfos(Lists.newArrayList( |
472 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), | 473 | DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), |
473 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), | 474 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), |
474 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() | 475 | DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build() |
475 | )) | 476 | )) |
476 | - .clientRegistrations(Sets.newHashSet( | 477 | + .clientRegistrations(Lists.newArrayList( |
477 | validClientRegistrationDto(), | 478 | validClientRegistrationDto(), |
478 | validClientRegistrationDto(), | 479 | validClientRegistrationDto(), |
479 | validClientRegistrationDto(), | 480 | validClientRegistrationDto(), |
@@ -481,11 +482,11 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | @@ -481,11 +482,11 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { | ||
481 | )) | 482 | )) |
482 | .build(), | 483 | .build(), |
483 | OAuth2ClientsDomainParams.builder() | 484 | OAuth2ClientsDomainParams.builder() |
484 | - .domainInfos(Sets.newHashSet( | 485 | + .domainInfos(Lists.newArrayList( |
485 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), | 486 | DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(), |
486 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() | 487 | DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() |
487 | )) | 488 | )) |
488 | - .clientRegistrations(Sets.newHashSet( | 489 | + .clientRegistrations(Lists.newArrayList( |
489 | validClientRegistrationDto(), | 490 | validClientRegistrationDto(), |
490 | validClientRegistrationDto() | 491 | validClientRegistrationDto() |
491 | )) | 492 | )) |
@@ -41,4 +41,8 @@ export class OAuth2Service { | @@ -41,4 +41,8 @@ export class OAuth2Service { | ||
41 | return this.http.post<OAuth2ClientsParams>('/api/oauth2/config', OAuth2Setting, | 41 | return this.http.post<OAuth2ClientsParams>('/api/oauth2/config', OAuth2Setting, |
42 | defaultHttpOptionsFromConfig(config)); | 42 | defaultHttpOptionsFromConfig(config)); |
43 | } | 43 | } |
44 | + | ||
45 | + public getLoginProcessingUrl(config?: RequestConfig): Observable<string> { | ||
46 | + return this.http.get<string>(`/api/oauth2/loginProcessingUrl`, defaultHttpOptionsFromConfig(config)); | ||
47 | + } | ||
44 | } | 48 | } |
@@ -191,6 +191,11 @@ export class MenuService { | @@ -191,6 +191,11 @@ export class MenuService { | ||
191 | name: 'admin.security-settings', | 191 | name: 'admin.security-settings', |
192 | icon: 'security', | 192 | icon: 'security', |
193 | path: '/settings/security-settings' | 193 | path: '/settings/security-settings' |
194 | + }, | ||
195 | + { | ||
196 | + name: 'admin.oauth2.oauth2', | ||
197 | + icon: 'security', | ||
198 | + path: '/settings/oauth2' | ||
194 | } | 199 | } |
195 | ] | 200 | ] |
196 | } | 201 | } |
@@ -88,14 +88,20 @@ | @@ -88,14 +88,20 @@ | ||
88 | </fieldset> | 88 | </fieldset> |
89 | </div> | 89 | </div> |
90 | <div mat-dialog-actions fxLayout="row"> | 90 | <div mat-dialog-actions fxLayout="row"> |
91 | - <div fxLayout="row" *ngIf="alarm$ | async; let alarm;"> | 91 | + <button mat-button color="primary" |
92 | + type="button" | ||
93 | + [disabled]="(isLoading$ | async)" | ||
94 | + (click)="close()" cdkFocusInitial> | ||
95 | + {{ 'action.close' | translate }} | ||
96 | + </button> | ||
97 | + <span fxFlex></span> | ||
98 | + <div fxLayout="row" *ngIf="alarm$ | async; let alarm;" fxLayoutGap="8px"> | ||
92 | <button *ngIf="allowAcknowledgment && (alarm.status === alarmStatuses.ACTIVE_UNACK || | 99 | <button *ngIf="allowAcknowledgment && (alarm.status === alarmStatuses.ACTIVE_UNACK || |
93 | alarm.status === alarmStatuses.CLEARED_UNACK)" | 100 | alarm.status === alarmStatuses.CLEARED_UNACK)" |
94 | mat-raised-button | 101 | mat-raised-button |
95 | color="primary" | 102 | color="primary" |
96 | type="button" | 103 | type="button" |
97 | (click)="acknowledge()" | 104 | (click)="acknowledge()" |
98 | - style="margin-right: 20px;" | ||
99 | [disabled]="(isLoading$ | async)"> | 105 | [disabled]="(isLoading$ | async)"> |
100 | {{ 'alarm.acknowledge' | translate }} | 106 | {{ 'alarm.acknowledge' | translate }} |
101 | </button> | 107 | </button> |
@@ -109,12 +115,5 @@ | @@ -109,12 +115,5 @@ | ||
109 | {{ 'alarm.clear' | translate }} | 115 | {{ 'alarm.clear' | translate }} |
110 | </button> | 116 | </button> |
111 | </div> | 117 | </div> |
112 | - <span fxFlex></span> | ||
113 | - <button mat-button color="primary" | ||
114 | - type="button" | ||
115 | - [disabled]="(isLoading$ | async)" | ||
116 | - (click)="close()" cdkFocusInitial> | ||
117 | - {{ 'action.close' | translate }} | ||
118 | - </button> | ||
119 | </div> | 118 | </div> |
120 | </form> | 119 | </form> |
@@ -59,16 +59,16 @@ | @@ -59,16 +59,16 @@ | ||
59 | </fieldset> | 59 | </fieldset> |
60 | </div> | 60 | </div> |
61 | <div mat-dialog-actions fxLayoutAlign="end center"> | 61 | <div mat-dialog-actions fxLayoutAlign="end center"> |
62 | - <button mat-raised-button color="primary" | ||
63 | - type="submit" | ||
64 | - [disabled]="(isLoading$ | async) || entityAliasFormGroup.invalid || !entityAliasFormGroup.dirty"> | ||
65 | - {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
66 | - </button> | ||
67 | <button mat-button color="primary" | 62 | <button mat-button color="primary" |
68 | type="button" | 63 | type="button" |
69 | [disabled]="(isLoading$ | async)" | 64 | [disabled]="(isLoading$ | async)" |
70 | (click)="cancel()" cdkFocusInitial> | 65 | (click)="cancel()" cdkFocusInitial> |
71 | {{ 'action.cancel' | translate }} | 66 | {{ 'action.cancel' | translate }} |
72 | </button> | 67 | </button> |
68 | + <button mat-raised-button color="primary" | ||
69 | + type="submit" | ||
70 | + [disabled]="(isLoading$ | async) || entityAliasFormGroup.invalid || !entityAliasFormGroup.dirty"> | ||
71 | + {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
72 | + </button> | ||
73 | </div> | 73 | </div> |
74 | </form> | 74 | </form> |
@@ -95,11 +95,6 @@ | @@ -95,11 +95,6 @@ | ||
95 | {{ 'alias.add' | translate }} | 95 | {{ 'alias.add' | translate }} |
96 | </button> | 96 | </button> |
97 | <span fxFlex></span> | 97 | <span fxFlex></span> |
98 | - <button mat-raised-button color="primary" | ||
99 | - type="submit" | ||
100 | - [disabled]="(isLoading$ | async) || entityAliasesFormGroup.invalid || !entityAliasesFormGroup.dirty"> | ||
101 | - {{ 'action.save' | translate }} | ||
102 | - </button> | ||
103 | <button mat-button color="primary" | 98 | <button mat-button color="primary" |
104 | type="button" | 99 | type="button" |
105 | [disabled]="(isLoading$ | async)" | 100 | [disabled]="(isLoading$ | async)" |
@@ -107,5 +102,10 @@ | @@ -107,5 +102,10 @@ | ||
107 | cdkFocusInitial> | 102 | cdkFocusInitial> |
108 | {{ 'action.cancel' | translate }} | 103 | {{ 'action.cancel' | translate }} |
109 | </button> | 104 | </button> |
105 | + <button mat-raised-button color="primary" | ||
106 | + type="submit" | ||
107 | + [disabled]="(isLoading$ | async) || entityAliasesFormGroup.invalid || !entityAliasesFormGroup.dirty"> | ||
108 | + {{ 'action.save' | translate }} | ||
109 | + </button> | ||
110 | </div> | 110 | </div> |
111 | </form> | 111 | </form> |
@@ -44,16 +44,16 @@ | @@ -44,16 +44,16 @@ | ||
44 | </fieldset> | 44 | </fieldset> |
45 | </div> | 45 | </div> |
46 | <div mat-dialog-actions fxLayoutAlign="end center"> | 46 | <div mat-dialog-actions fxLayoutAlign="end center"> |
47 | - <button mat-raised-button color="primary" | ||
48 | - type="submit" | ||
49 | - [disabled]="(isLoading$ | async) || attributeFormGroup.invalid || !attributeFormGroup.dirty"> | ||
50 | - {{ 'action.add' | translate }} | ||
51 | - </button> | ||
52 | <button mat-button color="primary" | 47 | <button mat-button color="primary" |
53 | type="button" | 48 | type="button" |
54 | [disabled]="(isLoading$ | async)" | 49 | [disabled]="(isLoading$ | async)" |
55 | (click)="cancel()" cdkFocusInitial> | 50 | (click)="cancel()" cdkFocusInitial> |
56 | {{ 'action.cancel' | translate }} | 51 | {{ 'action.cancel' | translate }} |
57 | </button> | 52 | </button> |
53 | + <button mat-raised-button color="primary" | ||
54 | + type="submit" | ||
55 | + [disabled]="(isLoading$ | async) || attributeFormGroup.invalid || !attributeFormGroup.dirty"> | ||
56 | + {{ 'action.add' | translate }} | ||
57 | + </button> | ||
58 | </div> | 58 | </div> |
59 | </form> | 59 | </form> |
@@ -55,21 +55,22 @@ | @@ -55,21 +55,22 @@ | ||
55 | </mat-radio-group> | 55 | </mat-radio-group> |
56 | </fieldset> | 56 | </fieldset> |
57 | </div> | 57 | </div> |
58 | - <div mat-dialog-actions fxLayoutAlign="end center"> | 58 | + <div mat-dialog-actions fxLayout="row"> |
59 | <mat-checkbox formControlName="openDashboard" | 59 | <mat-checkbox formControlName="openDashboard" |
60 | - style="margin-bottom: 0; padding-right: 20px;"> | 60 | + style="margin-bottom: 0;"> |
61 | {{ 'dashboard.open-dashboard' | translate }} | 61 | {{ 'dashboard.open-dashboard' | translate }} |
62 | </mat-checkbox> | 62 | </mat-checkbox> |
63 | - <button mat-raised-button color="primary" | ||
64 | - type="submit" | ||
65 | - [disabled]="(isLoading$ | async) || addWidgetFormGroup.invalid || !addWidgetFormGroup.dirty"> | ||
66 | - {{ 'action.add' | translate }} | ||
67 | - </button> | 63 | + <span fxFlex></span> |
68 | <button mat-button color="primary" | 64 | <button mat-button color="primary" |
69 | type="button" | 65 | type="button" |
70 | [disabled]="(isLoading$ | async)" | 66 | [disabled]="(isLoading$ | async)" |
71 | (click)="cancel()" cdkFocusInitial> | 67 | (click)="cancel()" cdkFocusInitial> |
72 | {{ 'action.cancel' | translate }} | 68 | {{ 'action.cancel' | translate }} |
73 | </button> | 69 | </button> |
70 | + <button mat-raised-button color="primary" | ||
71 | + type="submit" | ||
72 | + [disabled]="(isLoading$ | async) || addWidgetFormGroup.invalid || !addWidgetFormGroup.dirty"> | ||
73 | + {{ 'action.add' | translate }} | ||
74 | + </button> | ||
74 | </div> | 75 | </div> |
75 | </form> | 76 | </form> |
@@ -26,7 +26,6 @@ | @@ -26,7 +26,6 @@ | ||
26 | <div fxLayout="row" class="tb-panel-actions"> | 26 | <div fxLayout="row" class="tb-panel-actions"> |
27 | <span fxFlex></span> | 27 | <span fxFlex></span> |
28 | <button mat-button color="primary" | 28 | <button mat-button color="primary" |
29 | - style="margin-right: 20px;" | ||
30 | type="button" | 29 | type="button" |
31 | [disabled]="(isLoading$ | async)" | 30 | [disabled]="(isLoading$ | async)" |
32 | (click)="cancel()" cdkFocusInitial> | 31 | (click)="cancel()" cdkFocusInitial> |
@@ -40,11 +40,6 @@ | @@ -40,11 +40,6 @@ | ||
40 | </fieldset> | 40 | </fieldset> |
41 | </div> | 41 | </div> |
42 | <div mat-dialog-actions fxLayoutAlign="end center"> | 42 | <div mat-dialog-actions fxLayoutAlign="end center"> |
43 | - <button mat-raised-button color="primary" | ||
44 | - type="submit" | ||
45 | - [disabled]="(isLoading$ | async) || stateFormGroup.invalid"> | ||
46 | - {{ 'action.select' | translate }} | ||
47 | - </button> | ||
48 | <button mat-button color="primary" | 43 | <button mat-button color="primary" |
49 | type="button" | 44 | type="button" |
50 | [disabled]="(isLoading$ | async)" | 45 | [disabled]="(isLoading$ | async)" |
@@ -52,5 +47,10 @@ | @@ -52,5 +47,10 @@ | ||
52 | cdkFocusInitial> | 47 | cdkFocusInitial> |
53 | {{ 'action.cancel' | translate }} | 48 | {{ 'action.cancel' | translate }} |
54 | </button> | 49 | </button> |
50 | + <button mat-raised-button color="primary" | ||
51 | + type="submit" | ||
52 | + [disabled]="(isLoading$ | async) || stateFormGroup.invalid"> | ||
53 | + {{ 'action.select' | translate }} | ||
54 | + </button> | ||
55 | </div> | 55 | </div> |
56 | </form> | 56 | </form> |
@@ -31,7 +31,6 @@ | @@ -31,7 +31,6 @@ | ||
31 | <div mat-dialog-actions fxLayout="row"> | 31 | <div mat-dialog-actions fxLayout="row"> |
32 | <span fxFlex></span> | 32 | <span fxFlex></span> |
33 | <button mat-button color="primary" | 33 | <button mat-button color="primary" |
34 | - style="margin-right: 20px;" | ||
35 | type="button" | 34 | type="button" |
36 | [disabled]="(isLoading$ | async)" | 35 | [disabled]="(isLoading$ | async)" |
37 | [mat-dialog-close]="false" cdkFocusInitial> | 36 | [mat-dialog-close]="false" cdkFocusInitial> |
@@ -46,12 +46,6 @@ | @@ -46,12 +46,6 @@ | ||
46 | </fieldset> | 46 | </fieldset> |
47 | </div> | 47 | </div> |
48 | <div mat-dialog-actions fxLayoutAlign="end center"> | 48 | <div mat-dialog-actions fxLayoutAlign="end center"> |
49 | - <button mat-raised-button color="primary" | ||
50 | - *ngIf="!data.readonly" | ||
51 | - type="submit" | ||
52 | - [disabled]="(isLoading$ | async) || complexFilterFormGroup.invalid || !complexFilterFormGroup.dirty"> | ||
53 | - {{ (isAdd ? 'action.add' : 'action.update') | translate }} | ||
54 | - </button> | ||
55 | <button mat-button color="primary" | 49 | <button mat-button color="primary" |
56 | type="button" | 50 | type="button" |
57 | [disabled]="(isLoading$ | async)" | 51 | [disabled]="(isLoading$ | async)" |
@@ -59,5 +53,11 @@ | @@ -59,5 +53,11 @@ | ||
59 | cdkFocusInitial> | 53 | cdkFocusInitial> |
60 | {{ (data.readonly ? 'action.close' : 'action.cancel') | translate }} | 54 | {{ (data.readonly ? 'action.close' : 'action.cancel') | translate }} |
61 | </button> | 55 | </button> |
56 | + <button mat-raised-button color="primary" | ||
57 | + *ngIf="!data.readonly" | ||
58 | + type="submit" | ||
59 | + [disabled]="(isLoading$ | async) || complexFilterFormGroup.invalid || !complexFilterFormGroup.dirty"> | ||
60 | + {{ (isAdd ? 'action.add' : 'action.update') | translate }} | ||
61 | + </button> | ||
62 | </div> | 62 | </div> |
63 | </form> | 63 | </form> |
@@ -55,16 +55,16 @@ | @@ -55,16 +55,16 @@ | ||
55 | </fieldset> | 55 | </fieldset> |
56 | </div> | 56 | </div> |
57 | <div mat-dialog-actions fxLayoutAlign="end center"> | 57 | <div mat-dialog-actions fxLayoutAlign="end center"> |
58 | - <button mat-raised-button color="primary" | ||
59 | - type="submit" | ||
60 | - [disabled]="(isLoading$ | async) || filterFormGroup.invalid || !filterFormGroup.dirty"> | ||
61 | - {{ (isAdd ? 'action.add' : 'action.update') | translate }} | ||
62 | - </button> | ||
63 | <button mat-button color="primary" | 58 | <button mat-button color="primary" |
64 | type="button" | 59 | type="button" |
65 | [disabled]="(isLoading$ | async)" | 60 | [disabled]="(isLoading$ | async)" |
66 | (click)="cancel()" cdkFocusInitial> | 61 | (click)="cancel()" cdkFocusInitial> |
67 | {{ 'action.cancel' | translate }} | 62 | {{ 'action.cancel' | translate }} |
68 | </button> | 63 | </button> |
64 | + <button mat-raised-button color="primary" | ||
65 | + type="submit" | ||
66 | + [disabled]="(isLoading$ | async) || filterFormGroup.invalid || !filterFormGroup.dirty"> | ||
67 | + {{ (isAdd ? 'action.add' : 'action.update') | translate }} | ||
68 | + </button> | ||
69 | </div> | 69 | </div> |
70 | </form> | 70 | </form> |
@@ -46,12 +46,6 @@ | @@ -46,12 +46,6 @@ | ||
46 | </fieldset> | 46 | </fieldset> |
47 | </div> | 47 | </div> |
48 | <div mat-dialog-actions fxLayoutAlign="end center"> | 48 | <div mat-dialog-actions fxLayoutAlign="end center"> |
49 | - <button mat-raised-button color="primary" | ||
50 | - *ngIf="!data.readonly" | ||
51 | - type="submit" | ||
52 | - [disabled]="(isLoading$ | async) || filterUserInfoFormGroup.invalid || !filterUserInfoFormGroup.dirty"> | ||
53 | - {{ 'action.update' | translate }} | ||
54 | - </button> | ||
55 | <button mat-button color="primary" | 49 | <button mat-button color="primary" |
56 | type="button" | 50 | type="button" |
57 | [disabled]="(isLoading$ | async)" | 51 | [disabled]="(isLoading$ | async)" |
@@ -59,5 +53,11 @@ | @@ -59,5 +53,11 @@ | ||
59 | cdkFocusInitial> | 53 | cdkFocusInitial> |
60 | {{ (data.readonly ? 'action.close' : 'action.cancel') | translate }} | 54 | {{ (data.readonly ? 'action.close' : 'action.cancel') | translate }} |
61 | </button> | 55 | </button> |
56 | + <button mat-raised-button color="primary" | ||
57 | + *ngIf="!data.readonly" | ||
58 | + type="submit" | ||
59 | + [disabled]="(isLoading$ | async) || filterUserInfoFormGroup.invalid || !filterUserInfoFormGroup.dirty"> | ||
60 | + {{ 'action.update' | translate }} | ||
61 | + </button> | ||
62 | </div> | 62 | </div> |
63 | </form> | 63 | </form> |
@@ -88,11 +88,6 @@ | @@ -88,11 +88,6 @@ | ||
88 | {{ 'filter.add' | translate }} | 88 | {{ 'filter.add' | translate }} |
89 | </button> | 89 | </button> |
90 | <span fxFlex></span> | 90 | <span fxFlex></span> |
91 | - <button mat-raised-button color="primary" | ||
92 | - type="submit" | ||
93 | - [disabled]="(isLoading$ | async) || filtersFormGroup.invalid || !filtersFormGroup.dirty"> | ||
94 | - {{ 'action.save' | translate }} | ||
95 | - </button> | ||
96 | <button mat-button color="primary" | 91 | <button mat-button color="primary" |
97 | type="button" | 92 | type="button" |
98 | [disabled]="(isLoading$ | async)" | 93 | [disabled]="(isLoading$ | async)" |
@@ -100,5 +95,10 @@ | @@ -100,5 +95,10 @@ | ||
100 | cdkFocusInitial> | 95 | cdkFocusInitial> |
101 | {{ 'action.cancel' | translate }} | 96 | {{ 'action.cancel' | translate }} |
102 | </button> | 97 | </button> |
98 | + <button mat-raised-button color="primary" | ||
99 | + type="submit" | ||
100 | + [disabled]="(isLoading$ | async) || filtersFormGroup.invalid || !filtersFormGroup.dirty"> | ||
101 | + {{ 'action.save' | translate }} | ||
102 | + </button> | ||
103 | </div> | 103 | </div> |
104 | </form> | 104 | </form> |
@@ -79,12 +79,6 @@ | @@ -79,12 +79,6 @@ | ||
79 | </fieldset> | 79 | </fieldset> |
80 | </div> | 80 | </div> |
81 | <div mat-dialog-actions fxLayoutAlign="end center"> | 81 | <div mat-dialog-actions fxLayoutAlign="end center"> |
82 | - <button mat-raised-button color="primary" | ||
83 | - type="submit" | ||
84 | - *ngIf="!data.readonly" | ||
85 | - [disabled]="(isLoading$ | async) || keyFilterFormGroup.invalid || !keyFilterFormGroup.dirty"> | ||
86 | - {{ (data.isAdd ? 'action.add' : 'action.update') | translate }} | ||
87 | - </button> | ||
88 | <button mat-button color="primary" | 82 | <button mat-button color="primary" |
89 | type="button" | 83 | type="button" |
90 | [disabled]="(isLoading$ | async)" | 84 | [disabled]="(isLoading$ | async)" |
@@ -92,5 +86,11 @@ | @@ -92,5 +86,11 @@ | ||
92 | cdkFocusInitial> | 86 | cdkFocusInitial> |
93 | {{ (data.readonly ? 'action.close' : 'action.cancel') | translate }} | 87 | {{ (data.readonly ? 'action.close' : 'action.cancel') | translate }} |
94 | </button> | 88 | </button> |
89 | + <button mat-raised-button color="primary" | ||
90 | + type="submit" | ||
91 | + *ngIf="!data.readonly" | ||
92 | + [disabled]="(isLoading$ | async) || keyFilterFormGroup.invalid || !keyFilterFormGroup.dirty"> | ||
93 | + {{ (data.isAdd ? 'action.add' : 'action.update') | translate }} | ||
94 | + </button> | ||
95 | </div> | 95 | </div> |
96 | </form> | 96 | </form> |
@@ -65,16 +65,16 @@ | @@ -65,16 +65,16 @@ | ||
65 | </fieldset> | 65 | </fieldset> |
66 | </div> | 66 | </div> |
67 | <div mat-dialog-actions fxLayoutAlign="end center"> | 67 | <div mat-dialog-actions fxLayoutAlign="end center"> |
68 | - <button mat-raised-button color="primary" | ||
69 | - type="submit" | ||
70 | - [disabled]="(isLoading$ | async) || userFilterFormGroup.invalid || !userFilterFormGroup.dirty"> | ||
71 | - {{ 'action.update' | translate }} | ||
72 | - </button> | ||
73 | <button mat-button color="primary" | 68 | <button mat-button color="primary" |
74 | type="button" | 69 | type="button" |
75 | [disabled]="(isLoading$ | async)" | 70 | [disabled]="(isLoading$ | async)" |
76 | (click)="cancel()" cdkFocusInitial> | 71 | (click)="cancel()" cdkFocusInitial> |
77 | {{ 'action.cancel' | translate }} | 72 | {{ 'action.cancel' | translate }} |
78 | </button> | 73 | </button> |
74 | + <button mat-raised-button color="primary" | ||
75 | + type="submit" | ||
76 | + [disabled]="(isLoading$ | async) || userFilterFormGroup.invalid || !userFilterFormGroup.dirty"> | ||
77 | + {{ 'action.update' | translate }} | ||
78 | + </button> | ||
79 | </div> | 79 | </div> |
80 | </form> | 80 | </form> |
@@ -43,16 +43,16 @@ | @@ -43,16 +43,16 @@ | ||
43 | </fieldset> | 43 | </fieldset> |
44 | </div> | 44 | </div> |
45 | <div mat-dialog-actions fxLayoutAlign="end center"> | 45 | <div mat-dialog-actions fxLayoutAlign="end center"> |
46 | - <button mat-raised-button color="primary" | ||
47 | - type="submit" | ||
48 | - [disabled]="(isLoading$ | async) || importFormGroup.invalid || !importFormGroup.dirty"> | ||
49 | - {{ 'action.import' | translate }} | ||
50 | - </button> | ||
51 | <button mat-button color="primary" | 46 | <button mat-button color="primary" |
52 | type="button" | 47 | type="button" |
53 | [disabled]="(isLoading$ | async)" | 48 | [disabled]="(isLoading$ | async)" |
54 | (click)="cancel()" cdkFocusInitial> | 49 | (click)="cancel()" cdkFocusInitial> |
55 | {{ 'action.cancel' | translate }} | 50 | {{ 'action.cancel' | translate }} |
56 | </button> | 51 | </button> |
52 | + <button mat-raised-button color="primary" | ||
53 | + type="submit" | ||
54 | + [disabled]="(isLoading$ | async) || importFormGroup.invalid || !importFormGroup.dirty"> | ||
55 | + {{ 'action.import' | translate }} | ||
56 | + </button> | ||
57 | </div> | 57 | </div> |
58 | </form> | 58 | </form> |
@@ -108,17 +108,17 @@ | @@ -108,17 +108,17 @@ | ||
108 | </fieldset> | 108 | </fieldset> |
109 | </div> | 109 | </div> |
110 | <div mat-dialog-actions fxLayoutAlign="end center"> | 110 | <div mat-dialog-actions fxLayoutAlign="end center"> |
111 | - <button mat-raised-button color="primary" | ||
112 | - *ngIf="!readonly" | ||
113 | - type="submit" | ||
114 | - [disabled]="(isLoading$ | async) || conditionFormGroup.invalid || !conditionFormGroup.dirty"> | ||
115 | - {{ 'action.save' | translate }} | ||
116 | - </button> | ||
117 | <button mat-button color="primary" | 111 | <button mat-button color="primary" |
118 | type="button" | 112 | type="button" |
119 | [disabled]="(isLoading$ | async)" | 113 | [disabled]="(isLoading$ | async)" |
120 | (click)="cancel()" cdkFocusInitial> | 114 | (click)="cancel()" cdkFocusInitial> |
121 | {{ (readonly ? 'action.close' : 'action.cancel') | translate }} | 115 | {{ (readonly ? 'action.close' : 'action.cancel') | translate }} |
122 | </button> | 116 | </button> |
117 | + <button mat-raised-button color="primary" | ||
118 | + *ngIf="!readonly" | ||
119 | + type="submit" | ||
120 | + [disabled]="(isLoading$ | async) || conditionFormGroup.invalid || !conditionFormGroup.dirty"> | ||
121 | + {{ 'action.save' | translate }} | ||
122 | + </button> | ||
123 | </div> | 123 | </div> |
124 | </form> | 124 | </form> |
@@ -37,17 +37,17 @@ | @@ -37,17 +37,17 @@ | ||
37 | </fieldset> | 37 | </fieldset> |
38 | </div> | 38 | </div> |
39 | <div mat-dialog-actions fxLayoutAlign="end center"> | 39 | <div mat-dialog-actions fxLayoutAlign="end center"> |
40 | - <button mat-raised-button color="primary" | ||
41 | - *ngIf="!readonly" | ||
42 | - type="submit" | ||
43 | - [disabled]="(isLoading$ | async) || alarmScheduleFormGroup.invalid || !alarmScheduleFormGroup.dirty"> | ||
44 | - {{ 'action.save' | translate }} | ||
45 | - </button> | ||
46 | <button mat-button color="primary" | 40 | <button mat-button color="primary" |
47 | type="button" | 41 | type="button" |
48 | [disabled]="(isLoading$ | async)" | 42 | [disabled]="(isLoading$ | async)" |
49 | (click)="cancel()" cdkFocusInitial> | 43 | (click)="cancel()" cdkFocusInitial> |
50 | {{ (readonly ? 'action.close' : 'action.cancel') | translate }} | 44 | {{ (readonly ? 'action.close' : 'action.cancel') | translate }} |
51 | </button> | 45 | </button> |
46 | + <button mat-raised-button color="primary" | ||
47 | + *ngIf="!readonly" | ||
48 | + type="submit" | ||
49 | + [disabled]="(isLoading$ | async) || alarmScheduleFormGroup.invalid || !alarmScheduleFormGroup.dirty"> | ||
50 | + {{ 'action.save' | translate }} | ||
51 | + </button> | ||
52 | </div> | 52 | </div> |
53 | </form> | 53 | </form> |
@@ -47,9 +47,9 @@ | @@ -47,9 +47,9 @@ | ||
47 | <mat-icon>remove_circle_outline</mat-icon> | 47 | <mat-icon>remove_circle_outline</mat-icon> |
48 | </button> | 48 | </button> |
49 | </div> | 49 | </div> |
50 | - <div *ngIf="!createAlarmRulesFormArray().controls.length"> | 50 | + <div *ngIf="!createAlarmRulesFormArray().controls.length && !disabled"> |
51 | <span translate fxLayoutAlign="center center" style="margin: 16px 0" | 51 | <span translate fxLayoutAlign="center center" style="margin: 16px 0" |
52 | - class="tb-prompt">device-profile.no-create-alarm-rules</span> | 52 | + class="tb-prompt required">device-profile.add-create-alarm-rule-prompt</span> |
53 | </div> | 53 | </div> |
54 | <div fxLayout="row" *ngIf="!disabled"> | 54 | <div fxLayout="row" *ngIf="!disabled"> |
55 | <button mat-stroked-button color="primary" | 55 | <button mat-stroked-button color="primary" |
@@ -23,11 +23,11 @@ import { | @@ -23,11 +23,11 @@ import { | ||
23 | FormControl, | 23 | FormControl, |
24 | FormGroup, | 24 | FormGroup, |
25 | NG_VALIDATORS, | 25 | NG_VALIDATORS, |
26 | - NG_VALUE_ACCESSOR, | 26 | + NG_VALUE_ACCESSOR, ValidationErrors, |
27 | Validator, | 27 | Validator, |
28 | Validators | 28 | Validators |
29 | } from '@angular/forms'; | 29 | } from '@angular/forms'; |
30 | -import { AlarmRule } from '@shared/models/device.models'; | 30 | +import { AlarmRule, alarmRuleValidator } from '@shared/models/device.models'; |
31 | import { MatDialog } from '@angular/material/dialog'; | 31 | import { MatDialog } from '@angular/material/dialog'; |
32 | import { Subscription } from 'rxjs'; | 32 | import { Subscription } from 'rxjs'; |
33 | import { AlarmSeverity, alarmSeverityTranslations } from '../../../../../shared/models/alarm.models'; | 33 | import { AlarmSeverity, alarmSeverityTranslations } from '../../../../../shared/models/alarm.models'; |
@@ -141,10 +141,23 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, | @@ -141,10 +141,23 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, | ||
141 | }; | 141 | }; |
142 | const createAlarmRulesArray = this.createAlarmRulesFormGroup.get('createAlarmRules') as FormArray; | 142 | const createAlarmRulesArray = this.createAlarmRulesFormGroup.get('createAlarmRules') as FormArray; |
143 | createAlarmRulesArray.push(this.fb.group({ | 143 | createAlarmRulesArray.push(this.fb.group({ |
144 | - severity: [null, Validators.required], | ||
145 | - alarmRule: [createAlarmRule, Validators.required] | 144 | + severity: [this.getFirstUnusedSeverity(), Validators.required], |
145 | + alarmRule: [createAlarmRule, alarmRuleValidator] | ||
146 | })); | 146 | })); |
147 | this.createAlarmRulesFormGroup.updateValueAndValidity(); | 147 | this.createAlarmRulesFormGroup.updateValueAndValidity(); |
148 | + if (!this.createAlarmRulesFormGroup.valid) { | ||
149 | + this.updateModel(); | ||
150 | + } | ||
151 | + } | ||
152 | + | ||
153 | + private getFirstUnusedSeverity(): AlarmSeverity { | ||
154 | + for (const severityKey of Object.keys(AlarmSeverity)) { | ||
155 | + const severity = AlarmSeverity[severityKey]; | ||
156 | + if (this.usedSeverities.indexOf(severity) === -1) { | ||
157 | + return severity; | ||
158 | + } | ||
159 | + } | ||
160 | + return null; | ||
148 | } | 161 | } |
149 | 162 | ||
150 | public validate(c: FormControl) { | 163 | public validate(c: FormControl) { |
@@ -25,7 +25,7 @@ import { | @@ -25,7 +25,7 @@ import { | ||
25 | Validator, | 25 | Validator, |
26 | Validators | 26 | Validators |
27 | } from '@angular/forms'; | 27 | } from '@angular/forms'; |
28 | -import { AlarmRule, DeviceProfileAlarm } from '@shared/models/device.models'; | 28 | +import { AlarmRule, DeviceProfileAlarm, deviceProfileAlarmValidator } from '@shared/models/device.models'; |
29 | import { MatDialog } from '@angular/material/dialog'; | 29 | import { MatDialog } from '@angular/material/dialog'; |
30 | import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; | 30 | import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
31 | import { MatChipInputEvent } from '@angular/material/chips'; | 31 | import { MatChipInputEvent } from '@angular/material/chips'; |
@@ -92,7 +92,7 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit | @@ -92,7 +92,7 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit | ||
92 | clearRule: [null], | 92 | clearRule: [null], |
93 | propagate: [null], | 93 | propagate: [null], |
94 | propagateRelationTypes: [null] | 94 | propagateRelationTypes: [null] |
95 | - }); | 95 | + }, { validators: deviceProfileAlarmValidator }); |
96 | this.alarmFormGroup.valueChanges.subscribe(() => { | 96 | this.alarmFormGroup.valueChanges.subscribe(() => { |
97 | this.updateModel(); | 97 | this.updateModel(); |
98 | }); | 98 | }); |
@@ -30,7 +30,7 @@ import { | @@ -30,7 +30,7 @@ import { | ||
30 | import { Store } from '@ngrx/store'; | 30 | import { Store } from '@ngrx/store'; |
31 | import { AppState } from '@app/core/core.state'; | 31 | import { AppState } from '@app/core/core.state'; |
32 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; | 32 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
33 | -import { DeviceProfileAlarm } from '@shared/models/device.models'; | 33 | +import { DeviceProfileAlarm, deviceProfileAlarmValidator } from '@shared/models/device.models'; |
34 | import { guid } from '@core/utils'; | 34 | import { guid } from '@core/utils'; |
35 | import { Subscription } from 'rxjs'; | 35 | import { Subscription } from 'rxjs'; |
36 | import { MatDialog } from '@angular/material/dialog'; | 36 | import { MatDialog } from '@angular/material/dialog'; |
@@ -141,7 +141,7 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni | @@ -141,7 +141,7 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni | ||
141 | id: guid(), | 141 | id: guid(), |
142 | alarmType: '', | 142 | alarmType: '', |
143 | createRules: { | 143 | createRules: { |
144 | - empty: { | 144 | + CRITICAL: { |
145 | condition: { | 145 | condition: { |
146 | condition: [] | 146 | condition: [] |
147 | } | 147 | } |
@@ -149,8 +149,11 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni | @@ -149,8 +149,11 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni | ||
149 | } | 149 | } |
150 | }; | 150 | }; |
151 | const alarmsArray = this.deviceProfileAlarmsFormGroup.get('alarms') as FormArray; | 151 | const alarmsArray = this.deviceProfileAlarmsFormGroup.get('alarms') as FormArray; |
152 | - alarmsArray.push(this.fb.control(alarm, [Validators.required])); | 152 | + alarmsArray.push(this.fb.control(alarm, [deviceProfileAlarmValidator])); |
153 | this.deviceProfileAlarmsFormGroup.updateValueAndValidity(); | 153 | this.deviceProfileAlarmsFormGroup.updateValueAndValidity(); |
154 | + if (!this.deviceProfileAlarmsFormGroup.valid) { | ||
155 | + this.updateModel(); | ||
156 | + } | ||
154 | } | 157 | } |
155 | 158 | ||
156 | public validate(c: FormControl) { | 159 | public validate(c: FormControl) { |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<form (ngSubmit)="save()" style="min-width: 1000px;"> | 18 | +<form (ngSubmit)="save()" style="width: 1000px;"> |
19 | <mat-toolbar color="primary"> | 19 | <mat-toolbar color="primary"> |
20 | <h2>{{ (isAdd ? 'device-profile.add' : 'device-profile.edit' ) | translate }}</h2> | 20 | <h2>{{ (isAdd ? 'device-profile.add' : 'device-profile.edit' ) | translate }}</h2> |
21 | <span fxFlex></span> | 21 | <span fxFlex></span> |
@@ -37,11 +37,6 @@ | @@ -37,11 +37,6 @@ | ||
37 | </tb-device-profile> | 37 | </tb-device-profile> |
38 | </div> | 38 | </div> |
39 | <div mat-dialog-actions fxLayoutAlign="end center"> | 39 | <div mat-dialog-actions fxLayoutAlign="end center"> |
40 | - <button mat-raised-button color="primary" | ||
41 | - type="submit" | ||
42 | - [disabled]="(isLoading$ | async) || deviceProfileComponent.entityForm?.invalid || !deviceProfileComponent.entityForm?.dirty"> | ||
43 | - {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
44 | - </button> | ||
45 | <button mat-button color="primary" | 40 | <button mat-button color="primary" |
46 | type="button" | 41 | type="button" |
47 | cdkFocusInitial | 42 | cdkFocusInitial |
@@ -49,5 +44,10 @@ | @@ -49,5 +44,10 @@ | ||
49 | (click)="cancel()"> | 44 | (click)="cancel()"> |
50 | {{ 'action.cancel' | translate }} | 45 | {{ 'action.cancel' | translate }} |
51 | </button> | 46 | </button> |
47 | + <button mat-raised-button color="primary" | ||
48 | + type="submit" | ||
49 | + [disabled]="(isLoading$ | async) || deviceProfileComponent.entityForm?.invalid || !deviceProfileComponent.entityForm?.dirty"> | ||
50 | + {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
51 | + </button> | ||
52 | </div> | 52 | </div> |
53 | </form> | 53 | </form> |
@@ -41,7 +41,7 @@ | @@ -41,7 +41,7 @@ | ||
41 | </div> | 41 | </div> |
42 | <div class="mat-padding" fxLayout="column"> | 42 | <div class="mat-padding" fxLayout="column"> |
43 | <form [formGroup]="entityForm"> | 43 | <form [formGroup]="entityForm"> |
44 | - <fieldset [disabled]="(isLoading$ | async) || !isEdit"> | 44 | + <fieldset [disabled]="(isLoading$ | async) || !isEdit" style="min-width: 0;"> |
45 | <mat-form-field class="mat-block"> | 45 | <mat-form-field class="mat-block"> |
46 | <mat-label translate>device-profile.name</mat-label> | 46 | <mat-label translate>device-profile.name</mat-label> |
47 | <input matInput formControlName="name" required/> | 47 | <input matInput formControlName="name" required/> |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<form (ngSubmit)="save()" style="min-width: 600px;"> | 18 | +<form (ngSubmit)="save()" style="width: 600px;"> |
19 | <mat-toolbar color="primary"> | 19 | <mat-toolbar color="primary"> |
20 | <h2>{{ (isAdd ? 'tenant-profile.add' : 'tenant-profile.edit' ) | translate }}</h2> | 20 | <h2>{{ (isAdd ? 'tenant-profile.add' : 'tenant-profile.edit' ) | translate }}</h2> |
21 | <span fxFlex></span> | 21 | <span fxFlex></span> |
@@ -37,11 +37,6 @@ | @@ -37,11 +37,6 @@ | ||
37 | </tb-tenant-profile> | 37 | </tb-tenant-profile> |
38 | </div> | 38 | </div> |
39 | <div mat-dialog-actions fxLayoutAlign="end center"> | 39 | <div mat-dialog-actions fxLayoutAlign="end center"> |
40 | - <button mat-raised-button color="primary" | ||
41 | - type="submit" | ||
42 | - [disabled]="(isLoading$ | async) || tenantProfileComponent.entityForm?.invalid || !tenantProfileComponent.entityForm?.dirty"> | ||
43 | - {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
44 | - </button> | ||
45 | <button mat-button color="primary" | 40 | <button mat-button color="primary" |
46 | type="button" | 41 | type="button" |
47 | cdkFocusInitial | 42 | cdkFocusInitial |
@@ -49,5 +44,10 @@ | @@ -49,5 +44,10 @@ | ||
49 | (click)="cancel()"> | 44 | (click)="cancel()"> |
50 | {{ 'action.cancel' | translate }} | 45 | {{ 'action.cancel' | translate }} |
51 | </button> | 46 | </button> |
47 | + <button mat-raised-button color="primary" | ||
48 | + type="submit" | ||
49 | + [disabled]="(isLoading$ | async) || tenantProfileComponent.entityForm?.invalid || !tenantProfileComponent.entityForm?.dirty"> | ||
50 | + {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
51 | + </button> | ||
52 | </div> | 52 | </div> |
53 | </form> | 53 | </form> |
@@ -53,17 +53,16 @@ | @@ -53,17 +53,16 @@ | ||
53 | </div> | 53 | </div> |
54 | <div mat-dialog-actions fxLayout="row"> | 54 | <div mat-dialog-actions fxLayout="row"> |
55 | <span fxFlex></span> | 55 | <span fxFlex></span> |
56 | - <button mat-button mat-raised-button color="primary" | ||
57 | - type="submit" | ||
58 | - [disabled]="(isLoading$ | async) || relationFormGroup.invalid || !(relationFormGroup.dirty || additionalInfo.dirty)"> | ||
59 | - {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
60 | - </button> | ||
61 | <button mat-button color="primary" | 56 | <button mat-button color="primary" |
62 | - style="margin-right: 20px;" | ||
63 | type="button" | 57 | type="button" |
64 | [disabled]="(isLoading$ | async)" | 58 | [disabled]="(isLoading$ | async)" |
65 | (click)="cancel()" cdkFocusInitial> | 59 | (click)="cancel()" cdkFocusInitial> |
66 | {{ 'action.cancel' | translate }} | 60 | {{ 'action.cancel' | translate }} |
67 | </button> | 61 | </button> |
62 | + <button mat-button mat-raised-button color="primary" | ||
63 | + type="submit" | ||
64 | + [disabled]="(isLoading$ | async) || relationFormGroup.invalid || !(relationFormGroup.dirty || additionalInfo.dirty)"> | ||
65 | + {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
66 | + </button> | ||
68 | </div> | 67 | </div> |
69 | </form> | 68 | </form> |
@@ -147,16 +147,16 @@ | @@ -147,16 +147,16 @@ | ||
147 | </fieldset> | 147 | </fieldset> |
148 | </div> | 148 | </div> |
149 | <div mat-dialog-actions fxLayoutAlign="end center"> | 149 | <div mat-dialog-actions fxLayoutAlign="end center"> |
150 | - <button mat-raised-button color="primary" | ||
151 | - type="submit" | ||
152 | - [disabled]="(isLoading$ | async) || widgetActionFormGroup.invalid || actionTypeFormGroup.invalid || (!widgetActionFormGroup.dirty && !actionTypeFormGroup.dirty)"> | ||
153 | - {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
154 | - </button> | ||
155 | <button mat-button color="primary" | 150 | <button mat-button color="primary" |
156 | type="button" | 151 | type="button" |
157 | [disabled]="(isLoading$ | async)" | 152 | [disabled]="(isLoading$ | async)" |
158 | (click)="cancel()" cdkFocusInitial> | 153 | (click)="cancel()" cdkFocusInitial> |
159 | {{ 'action.cancel' | translate }} | 154 | {{ 'action.cancel' | translate }} |
160 | </button> | 155 | </button> |
156 | + <button mat-raised-button color="primary" | ||
157 | + type="submit" | ||
158 | + [disabled]="(isLoading$ | async) || widgetActionFormGroup.invalid || actionTypeFormGroup.invalid || (!widgetActionFormGroup.dirty && !actionTypeFormGroup.dirty)"> | ||
159 | + {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
160 | + </button> | ||
161 | </div> | 161 | </div> |
162 | </form> | 162 | </form> |
@@ -38,16 +38,16 @@ | @@ -38,16 +38,16 @@ | ||
38 | </tb-data-key-config> | 38 | </tb-data-key-config> |
39 | </div> | 39 | </div> |
40 | <div mat-dialog-actions fxLayoutAlign="end center"> | 40 | <div mat-dialog-actions fxLayoutAlign="end center"> |
41 | - <button mat-raised-button color="primary" | ||
42 | - type="submit" | ||
43 | - [disabled]="(isLoading$ | async) || dataKeyFormGroup.invalid || !dataKeyFormGroup.dirty"> | ||
44 | - {{ 'action.save' | translate }} | ||
45 | - </button> | ||
46 | <button mat-button color="primary" | 41 | <button mat-button color="primary" |
47 | type="button" | 42 | type="button" |
48 | [disabled]="(isLoading$ | async)" | 43 | [disabled]="(isLoading$ | async)" |
49 | (click)="cancel()" cdkFocusInitial> | 44 | (click)="cancel()" cdkFocusInitial> |
50 | {{ 'action.cancel' | translate }} | 45 | {{ 'action.cancel' | translate }} |
51 | </button> | 46 | </button> |
47 | + <button mat-raised-button color="primary" | ||
48 | + type="submit" | ||
49 | + [disabled]="(isLoading$ | async) || dataKeyFormGroup.invalid || !dataKeyFormGroup.dirty"> | ||
50 | + {{ 'action.save' | translate }} | ||
51 | + </button> | ||
52 | </div> | 52 | </div> |
53 | </form> | 53 | </form> |
@@ -50,17 +50,16 @@ | @@ -50,17 +50,16 @@ | ||
50 | </mat-chip-list> | 50 | </mat-chip-list> |
51 | </mat-form-field> | 51 | </mat-form-field> |
52 | <div fxLayout="row" class="tb-panel-actions" fxLayoutAlign="end center"> | 52 | <div fxLayout="row" class="tb-panel-actions" fxLayoutAlign="end center"> |
53 | + <button type="button" | ||
54 | + mat-button | ||
55 | + (click)="cancel()"> | ||
56 | + {{ 'action.cancel' | translate }} | ||
57 | + </button> | ||
53 | <button type="submit" | 58 | <button type="submit" |
54 | mat-raised-button | 59 | mat-raised-button |
55 | color="primary" | 60 | color="primary" |
56 | [disabled]="alarmFilterFormGroup.invalid || !alarmFilterFormGroup.dirty"> | 61 | [disabled]="alarmFilterFormGroup.invalid || !alarmFilterFormGroup.dirty"> |
57 | {{ 'action.update' | translate }} | 62 | {{ 'action.update' | translate }} |
58 | </button> | 63 | </button> |
59 | - <button type="button" | ||
60 | - mat-button | ||
61 | - (click)="cancel()" | ||
62 | - style="margin-right: 20px;"> | ||
63 | - {{ 'action.cancel' | translate }} | ||
64 | - </button> | ||
65 | </div> | 64 | </div> |
66 | </form> | 65 | </form> |
@@ -28,7 +28,6 @@ | @@ -28,7 +28,6 @@ | ||
28 | <div class="tb-panel-actions" fxLayout="row" *ngIf="!settings.autoConfirm"> | 28 | <div class="tb-panel-actions" fxLayout="row" *ngIf="!settings.autoConfirm"> |
29 | <span fxFlex></span> | 29 | <span fxFlex></span> |
30 | <button mat-button mat-raised-button color="primary" | 30 | <button mat-button mat-raised-button color="primary" |
31 | - style="margin-right: 20px;" | ||
32 | type="button" (click)="apply()"> | 31 | type="button" (click)="apply()"> |
33 | {{ 'action.ok' | translate }} | 32 | {{ 'action.ok' | translate }} |
34 | </button> | 33 | </button> |
@@ -352,7 +352,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni | @@ -352,7 +352,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni | ||
352 | } | 352 | } |
353 | dataKeys.push(dataKey); | 353 | dataKeys.push(dataKey); |
354 | 354 | ||
355 | - dataKey.title = this.utils.customTranslation(dataKey.label, dataKey.label); | 355 | + dataKey.label = this.utils.customTranslation(dataKey.label, dataKey.label); |
356 | + dataKey.title = dataKey.label; | ||
356 | dataKey.def = 'def' + this.columns.length; | 357 | dataKey.def = 'def' + this.columns.length; |
357 | const keySettings: TableWidgetDataKeySettings = dataKey.settings; | 358 | const keySettings: TableWidgetDataKeySettings = dataKey.settings; |
358 | if (dataKey.type === DataKeyType.entityField && | 359 | if (dataKey.type === DataKeyType.entityField && |
@@ -374,7 +375,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni | @@ -374,7 +375,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni | ||
374 | } | 375 | } |
375 | 376 | ||
376 | if (this.settings.defaultSortOrder && this.settings.defaultSortOrder.length) { | 377 | if (this.settings.defaultSortOrder && this.settings.defaultSortOrder.length) { |
377 | - this.defaultSortOrder = this.settings.defaultSortOrder; | 378 | + this.defaultSortOrder = this.utils.customTranslation(this.settings.defaultSortOrder, this.settings.defaultSortOrder); |
378 | } | 379 | } |
379 | 380 | ||
380 | this.pageLink.sortOrder = entityDataSortOrderFromString(this.defaultSortOrder, this.columns); | 381 | this.pageLink.sortOrder = entityDataSortOrderFromString(this.defaultSortOrder, this.columns); |
@@ -40,17 +40,17 @@ | @@ -40,17 +40,17 @@ | ||
40 | </fieldset> | 40 | </fieldset> |
41 | </div> | 41 | </div> |
42 | <div mat-dialog-actions fxLayoutAlign="end center"> | 42 | <div mat-dialog-actions fxLayoutAlign="end center"> |
43 | - <button mat-raised-button color="primary" | ||
44 | - type="submit" | ||
45 | - [disabled]="(isLoading$ | async) || addEntitiesToCustomerFormGroup.invalid | ||
46 | - || !addEntitiesToCustomerFormGroup.dirty"> | ||
47 | - {{ 'action.assign' | translate }} | ||
48 | - </button> | ||
49 | <button mat-button color="primary" | 43 | <button mat-button color="primary" |
50 | type="button" | 44 | type="button" |
51 | [disabled]="(isLoading$ | async)" | 45 | [disabled]="(isLoading$ | async)" |
52 | (click)="cancel()" cdkFocusInitial> | 46 | (click)="cancel()" cdkFocusInitial> |
53 | {{ 'action.cancel' | translate }} | 47 | {{ 'action.cancel' | translate }} |
54 | </button> | 48 | </button> |
49 | + <button mat-raised-button color="primary" | ||
50 | + type="submit" | ||
51 | + [disabled]="(isLoading$ | async) || addEntitiesToCustomerFormGroup.invalid | ||
52 | + || !addEntitiesToCustomerFormGroup.dirty"> | ||
53 | + {{ 'action.assign' | translate }} | ||
54 | + </button> | ||
55 | </div> | 55 | </div> |
56 | </form> | 56 | </form> |
@@ -39,17 +39,17 @@ | @@ -39,17 +39,17 @@ | ||
39 | </fieldset> | 39 | </fieldset> |
40 | </div> | 40 | </div> |
41 | <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center"> | 41 | <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center"> |
42 | - <button mat-raised-button color="primary" | ||
43 | - type="submit" | ||
44 | - [disabled]="(isLoading$ | async) || assignToCustomerFormGroup.invalid | ||
45 | - || !assignToCustomerFormGroup.dirty"> | ||
46 | - {{ 'action.assign' | translate }} | ||
47 | - </button> | ||
48 | <button mat-button color="primary" | 42 | <button mat-button color="primary" |
49 | type="button" | 43 | type="button" |
50 | [disabled]="(isLoading$ | async)" | 44 | [disabled]="(isLoading$ | async)" |
51 | (click)="cancel()" cdkFocusInitial> | 45 | (click)="cancel()" cdkFocusInitial> |
52 | {{ 'action.cancel' | translate }} | 46 | {{ 'action.cancel' | translate }} |
53 | </button> | 47 | </button> |
48 | + <button mat-raised-button color="primary" | ||
49 | + type="submit" | ||
50 | + [disabled]="(isLoading$ | async) || assignToCustomerFormGroup.invalid | ||
51 | + || !assignToCustomerFormGroup.dirty"> | ||
52 | + {{ 'action.assign' | translate }} | ||
53 | + </button> | ||
54 | </div> | 54 | </div> |
55 | </form> | 55 | </form> |
@@ -14,8 +14,8 @@ | @@ -14,8 +14,8 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { NgModule } from '@angular/core'; | ||
18 | -import { RouterModule, Routes } from '@angular/router'; | 17 | +import { Injectable, NgModule } from '@angular/core'; |
18 | +import { Resolve, RouterModule, Routes } from '@angular/router'; | ||
19 | 19 | ||
20 | import { MailServerComponent } from '@modules/home/pages/admin/mail-server.component'; | 20 | import { MailServerComponent } from '@modules/home/pages/admin/mail-server.component'; |
21 | import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; | 21 | import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; |
@@ -23,6 +23,25 @@ import { Authority } from '@shared/models/authority.enum'; | @@ -23,6 +23,25 @@ import { Authority } from '@shared/models/authority.enum'; | ||
23 | import { GeneralSettingsComponent } from '@modules/home/pages/admin/general-settings.component'; | 23 | import { GeneralSettingsComponent } from '@modules/home/pages/admin/general-settings.component'; |
24 | import { SecuritySettingsComponent } from '@modules/home/pages/admin/security-settings.component'; | 24 | import { SecuritySettingsComponent } from '@modules/home/pages/admin/security-settings.component'; |
25 | import { OAuth2SettingsComponent } from '@home/pages/admin/oauth2-settings.component'; | 25 | import { OAuth2SettingsComponent } from '@home/pages/admin/oauth2-settings.component'; |
26 | +import { User } from '@shared/models/user.model'; | ||
27 | +import { Store } from '@ngrx/store'; | ||
28 | +import { AppState } from '@core/core.state'; | ||
29 | +import { UserService } from '@core/http/user.service'; | ||
30 | +import { Observable } from 'rxjs'; | ||
31 | +import { getCurrentAuthUser } from '@core/auth/auth.selectors'; | ||
32 | +import { OAuth2Service } from '@core/http/oauth2.service'; | ||
33 | +import { UserProfileResolver } from '@home/pages/profile/profile-routing.module'; | ||
34 | + | ||
35 | +@Injectable() | ||
36 | +export class OAuth2LoginProcessingUrlResolver implements Resolve<string> { | ||
37 | + | ||
38 | + constructor(private oauth2Service: OAuth2Service) { | ||
39 | + } | ||
40 | + | ||
41 | + resolve(): Observable<string> { | ||
42 | + return this.oauth2Service.getLoginProcessingUrl(); | ||
43 | + } | ||
44 | +} | ||
26 | 45 | ||
27 | const routes: Routes = [ | 46 | const routes: Routes = [ |
28 | { | 47 | { |
@@ -90,6 +109,9 @@ const routes: Routes = [ | @@ -90,6 +109,9 @@ const routes: Routes = [ | ||
90 | label: 'admin.oauth2.oauth2', | 109 | label: 'admin.oauth2.oauth2', |
91 | icon: 'security' | 110 | icon: 'security' |
92 | } | 111 | } |
112 | + }, | ||
113 | + resolve: { | ||
114 | + loginProcessingUrl: OAuth2LoginProcessingUrlResolver | ||
93 | } | 115 | } |
94 | } | 116 | } |
95 | ] | 117 | ] |
@@ -98,6 +120,9 @@ const routes: Routes = [ | @@ -98,6 +120,9 @@ const routes: Routes = [ | ||
98 | 120 | ||
99 | @NgModule({ | 121 | @NgModule({ |
100 | imports: [RouterModule.forChild(routes)], | 122 | imports: [RouterModule.forChild(routes)], |
101 | - exports: [RouterModule] | 123 | + exports: [RouterModule], |
124 | + providers: [ | ||
125 | + OAuth2LoginProcessingUrlResolver | ||
126 | + ] | ||
102 | }) | 127 | }) |
103 | export class AdminRoutingModule { } | 128 | export class AdminRoutingModule { } |
@@ -43,6 +43,7 @@ import { DialogService } from '@core/services/dialog.service'; | @@ -43,6 +43,7 @@ import { DialogService } from '@core/services/dialog.service'; | ||
43 | import { TranslateService } from '@ngx-translate/core'; | 43 | import { TranslateService } from '@ngx-translate/core'; |
44 | import { isDefined, isDefinedAndNotNull } from '@core/utils'; | 44 | import { isDefined, isDefinedAndNotNull } from '@core/utils'; |
45 | import { OAuth2Service } from '@core/http/oauth2.service'; | 45 | import { OAuth2Service } from '@core/http/oauth2.service'; |
46 | +import { ActivatedRoute } from '@angular/router'; | ||
46 | 47 | ||
47 | @Component({ | 48 | @Component({ |
48 | selector: 'tb-oauth2-settings', | 49 | selector: 'tb-oauth2-settings', |
@@ -87,7 +88,10 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -87,7 +88,10 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
87 | 88 | ||
88 | templateProvider = ['Custom']; | 89 | templateProvider = ['Custom']; |
89 | 90 | ||
91 | + private loginProcessingUrl: string = this.route.snapshot.data.loginProcessingUrl; | ||
92 | + | ||
90 | constructor(protected store: Store<AppState>, | 93 | constructor(protected store: Store<AppState>, |
94 | + private route: ActivatedRoute, | ||
91 | private oauth2Service: OAuth2Service, | 95 | private oauth2Service: OAuth2Service, |
92 | private fb: FormBuilder, | 96 | private fb: FormBuilder, |
93 | private dialogService: DialogService, | 97 | private dialogService: DialogService, |
@@ -130,7 +134,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -130,7 +134,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
130 | return this.oauth2SettingsForm.get('domainsParams') as FormArray; | 134 | return this.oauth2SettingsForm.get('domainsParams') as FormArray; |
131 | } | 135 | } |
132 | 136 | ||
133 | - private formBasicGroup(mapperConfigBasic?: MapperConfigBasic): FormGroup { | 137 | + private formBasicGroup(type: MapperConfigType, mapperConfigBasic?: MapperConfigBasic): FormGroup { |
134 | let tenantNamePattern; | 138 | let tenantNamePattern; |
135 | if (mapperConfigBasic?.tenantNamePattern) { | 139 | if (mapperConfigBasic?.tenantNamePattern) { |
136 | tenantNamePattern = mapperConfigBasic.tenantNamePattern; | 140 | tenantNamePattern = mapperConfigBasic.tenantNamePattern; |
@@ -138,16 +142,20 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -138,16 +142,20 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
138 | tenantNamePattern = {value: null, disabled: true}; | 142 | tenantNamePattern = {value: null, disabled: true}; |
139 | } | 143 | } |
140 | const basicGroup = this.fb.group({ | 144 | const basicGroup = this.fb.group({ |
141 | - emailAttributeKey: [mapperConfigBasic?.emailAttributeKey ? mapperConfigBasic.emailAttributeKey : 'email', Validators.required], | ||
142 | firstNameAttributeKey: [mapperConfigBasic?.firstNameAttributeKey ? mapperConfigBasic.firstNameAttributeKey : ''], | 145 | firstNameAttributeKey: [mapperConfigBasic?.firstNameAttributeKey ? mapperConfigBasic.firstNameAttributeKey : ''], |
143 | lastNameAttributeKey: [mapperConfigBasic?.lastNameAttributeKey ? mapperConfigBasic.lastNameAttributeKey : ''], | 146 | lastNameAttributeKey: [mapperConfigBasic?.lastNameAttributeKey ? mapperConfigBasic.lastNameAttributeKey : ''], |
144 | tenantNameStrategy: [mapperConfigBasic?.tenantNameStrategy ? mapperConfigBasic.tenantNameStrategy : TenantNameStrategy.DOMAIN], | 147 | tenantNameStrategy: [mapperConfigBasic?.tenantNameStrategy ? mapperConfigBasic.tenantNameStrategy : TenantNameStrategy.DOMAIN], |
145 | tenantNamePattern: [tenantNamePattern, Validators.required], | 148 | tenantNamePattern: [tenantNamePattern, Validators.required], |
146 | customerNamePattern: [mapperConfigBasic?.customerNamePattern ? mapperConfigBasic.customerNamePattern : null], | 149 | customerNamePattern: [mapperConfigBasic?.customerNamePattern ? mapperConfigBasic.customerNamePattern : null], |
147 | defaultDashboardName: [mapperConfigBasic?.defaultDashboardName ? mapperConfigBasic.defaultDashboardName : null], | 150 | defaultDashboardName: [mapperConfigBasic?.defaultDashboardName ? mapperConfigBasic.defaultDashboardName : null], |
148 | - alwaysFullScreen: [mapperConfigBasic?.alwaysFullScreen ? mapperConfigBasic.alwaysFullScreen : false] | 151 | + alwaysFullScreen: [isDefinedAndNotNull(mapperConfigBasic?.alwaysFullScreen) ? mapperConfigBasic.alwaysFullScreen : false] |
149 | }); | 152 | }); |
150 | 153 | ||
154 | + if (MapperConfigType.GITHUB !== type) { | ||
155 | + basicGroup.addControl('emailAttributeKey', | ||
156 | + this.fb.control( mapperConfigBasic?.emailAttributeKey ? mapperConfigBasic.emailAttributeKey : 'email', Validators.required)); | ||
157 | + } | ||
158 | + | ||
151 | this.subscriptions.push(basicGroup.get('tenantNameStrategy').valueChanges.subscribe((domain) => { | 159 | this.subscriptions.push(basicGroup.get('tenantNameStrategy').valueChanges.subscribe((domain) => { |
152 | if (domain === 'CUSTOM') { | 160 | if (domain === 'CUSTOM') { |
153 | basicGroup.get('tenantNamePattern').enable(); | 161 | basicGroup.get('tenantNamePattern').enable(); |
@@ -279,9 +287,12 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -279,9 +287,12 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
279 | clientRegistration?.userNameAttributeName ? clientRegistration.userNameAttributeName : 'email', Validators.required], | 287 | clientRegistration?.userNameAttributeName ? clientRegistration.userNameAttributeName : 'email', Validators.required], |
280 | mapperConfig: this.fb.group({ | 288 | mapperConfig: this.fb.group({ |
281 | allowUserCreation: [ | 289 | allowUserCreation: [ |
282 | - clientRegistration?.mapperConfig?.allowUserCreation ? clientRegistration.mapperConfig.allowUserCreation : true | 290 | + isDefinedAndNotNull(clientRegistration?.mapperConfig?.allowUserCreation) ? |
291 | + clientRegistration.mapperConfig.allowUserCreation : true | ||
292 | + ], | ||
293 | + activateUser: [ | ||
294 | + isDefinedAndNotNull(clientRegistration?.mapperConfig?.activateUser) ? clientRegistration.mapperConfig.activateUser : false | ||
283 | ], | 295 | ], |
284 | - activateUser: [clientRegistration?.mapperConfig?.activateUser ? clientRegistration.mapperConfig.activateUser : false], | ||
285 | type: [ | 296 | type: [ |
286 | clientRegistration?.mapperConfig?.type ? clientRegistration.mapperConfig.type : MapperConfigType.BASIC, Validators.required | 297 | clientRegistration?.mapperConfig?.type ? clientRegistration.mapperConfig.type : MapperConfigType.BASIC, Validators.required |
287 | ] | 298 | ] |
@@ -308,7 +319,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -308,7 +319,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
308 | return clientRegistrationFormGroup; | 319 | return clientRegistrationFormGroup; |
309 | } | 320 | } |
310 | 321 | ||
311 | - private validateScope (control: AbstractControl): ValidationErrors | null { | 322 | + private validateScope(control: AbstractControl): ValidationErrors | null { |
312 | const scope: string[] = control.value; | 323 | const scope: string[] = control.value; |
313 | if (!scope || !scope.length) { | 324 | if (!scope || !scope.length) { |
314 | return { | 325 | return { |
@@ -347,7 +358,11 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -347,7 +358,11 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
347 | mapperConfig.addControl('custom', this.formCustomGroup(predefinedValue?.custom)); | 358 | mapperConfig.addControl('custom', this.formCustomGroup(predefinedValue?.custom)); |
348 | } else { | 359 | } else { |
349 | mapperConfig.removeControl('custom'); | 360 | mapperConfig.removeControl('custom'); |
350 | - mapperConfig.addControl('basic', this.formBasicGroup(predefinedValue?.basic)); | 361 | + if (mapperConfig.get('basic')) { |
362 | + mapperConfig.setControl('basic', this.formBasicGroup(type, predefinedValue?.basic)); | ||
363 | + } else { | ||
364 | + mapperConfig.addControl('basic', this.formBasicGroup(type, predefinedValue?.basic)); | ||
365 | + } | ||
351 | } | 366 | } |
352 | } | 367 | } |
353 | 368 | ||
@@ -490,7 +505,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -490,7 +505,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
490 | } else { | 505 | } else { |
491 | protocol = domainInfo.scheme === DomainSchema.MIXED ? DomainSchema.HTTPS.toLowerCase() : domainInfo.scheme.toLowerCase(); | 506 | protocol = domainInfo.scheme === DomainSchema.MIXED ? DomainSchema.HTTPS.toLowerCase() : domainInfo.scheme.toLowerCase(); |
492 | } | 507 | } |
493 | - return `${protocol}://${domainInfo.name}/login/oauth2/code/`; | 508 | + return `${protocol}://${domainInfo.name}${this.loginProcessingUrl}`; |
494 | } | 509 | } |
495 | return ''; | 510 | return ''; |
496 | } | 511 | } |
@@ -41,11 +41,6 @@ | @@ -41,11 +41,6 @@ | ||
41 | </fieldset> | 41 | </fieldset> |
42 | </div> | 42 | </div> |
43 | <div mat-dialog-actions fxLayoutAlign="end center"> | 43 | <div mat-dialog-actions fxLayoutAlign="end center"> |
44 | - <button mat-raised-button color="primary" | ||
45 | - type="submit" | ||
46 | - [disabled]="(isLoading$ | async) || widgetFormGroup.invalid"> | ||
47 | - {{ 'action.add' | translate }} | ||
48 | - </button> | ||
49 | <button mat-button color="primary" | 44 | <button mat-button color="primary" |
50 | type="button" | 45 | type="button" |
51 | [disabled]="(isLoading$ | async)" | 46 | [disabled]="(isLoading$ | async)" |
@@ -53,5 +48,10 @@ | @@ -53,5 +48,10 @@ | ||
53 | cdkFocusInitial> | 48 | cdkFocusInitial> |
54 | {{ 'action.cancel' | translate }} | 49 | {{ 'action.cancel' | translate }} |
55 | </button> | 50 | </button> |
51 | + <button mat-raised-button color="primary" | ||
52 | + type="submit" | ||
53 | + [disabled]="(isLoading$ | async) || widgetFormGroup.invalid"> | ||
54 | + {{ 'action.add' | translate }} | ||
55 | + </button> | ||
56 | </div> | 56 | </div> |
57 | </form> | 57 | </form> |
@@ -152,17 +152,17 @@ | @@ -152,17 +152,17 @@ | ||
152 | </fieldset> | 152 | </fieldset> |
153 | </div> | 153 | </div> |
154 | <div mat-dialog-actions fxLayoutAlign="end center"> | 154 | <div mat-dialog-actions fxLayoutAlign="end center"> |
155 | - <button mat-raised-button color="primary" | ||
156 | - type="submit" | ||
157 | - [disabled]="(isLoading$ | async) || settingsFormGroup.invalid || gridSettingsFormGroup.invalid | ||
158 | - || (!settingsFormGroup.dirty && !gridSettingsFormGroup.dirty)"> | ||
159 | - {{ 'action.save' | translate }} | ||
160 | - </button> | ||
161 | <button mat-button color="primary" | 155 | <button mat-button color="primary" |
162 | type="button" | 156 | type="button" |
163 | [disabled]="(isLoading$ | async)" | 157 | [disabled]="(isLoading$ | async)" |
164 | (click)="cancel()" cdkFocusInitial> | 158 | (click)="cancel()" cdkFocusInitial> |
165 | {{ 'action.cancel' | translate }} | 159 | {{ 'action.cancel' | translate }} |
166 | </button> | 160 | </button> |
161 | + <button mat-raised-button color="primary" | ||
162 | + type="submit" | ||
163 | + [disabled]="(isLoading$ | async) || settingsFormGroup.invalid || gridSettingsFormGroup.invalid | ||
164 | + || (!settingsFormGroup.dirty && !gridSettingsFormGroup.dirty)"> | ||
165 | + {{ 'action.save' | translate }} | ||
166 | + </button> | ||
167 | </div> | 167 | </div> |
168 | </form> | 168 | </form> |
@@ -54,11 +54,6 @@ | @@ -54,11 +54,6 @@ | ||
54 | </fieldset> | 54 | </fieldset> |
55 | </div> | 55 | </div> |
56 | <div mat-dialog-actions fxLayoutAlign="end center"> | 56 | <div mat-dialog-actions fxLayoutAlign="end center"> |
57 | - <button mat-raised-button color="primary" | ||
58 | - type="submit" | ||
59 | - [disabled]="(isLoading$ | async) || layoutsFormGroup.invalid || !layoutsFormGroup.dirty"> | ||
60 | - {{ 'action.save' | translate }} | ||
61 | - </button> | ||
62 | <button mat-button | 57 | <button mat-button |
63 | color="primary" | 58 | color="primary" |
64 | type="button" | 59 | type="button" |
@@ -66,5 +61,10 @@ | @@ -66,5 +61,10 @@ | ||
66 | (click)="cancel()" cdkFocusInitial> | 61 | (click)="cancel()" cdkFocusInitial> |
67 | {{ 'action.cancel' | translate }} | 62 | {{ 'action.cancel' | translate }} |
68 | </button> | 63 | </button> |
64 | + <button mat-raised-button color="primary" | ||
65 | + type="submit" | ||
66 | + [disabled]="(isLoading$ | async) || layoutsFormGroup.invalid || !layoutsFormGroup.dirty"> | ||
67 | + {{ 'action.save' | translate }} | ||
68 | + </button> | ||
69 | </div> | 69 | </div> |
70 | </form> | 70 | </form> |
@@ -54,7 +54,6 @@ | @@ -54,7 +54,6 @@ | ||
54 | <div mat-dialog-actions fxLayout="row"> | 54 | <div mat-dialog-actions fxLayout="row"> |
55 | <span fxFlex></span> | 55 | <span fxFlex></span> |
56 | <button mat-button color="primary" | 56 | <button mat-button color="primary" |
57 | - style="margin-right: 20px;" | ||
58 | type="button" | 57 | type="button" |
59 | [disabled]="(isLoading$ | async)" | 58 | [disabled]="(isLoading$ | async)" |
60 | (click)="close()" cdkFocusInitial> | 59 | (click)="close()" cdkFocusInitial> |
@@ -41,18 +41,17 @@ | @@ -41,18 +41,17 @@ | ||
41 | </div> | 41 | </div> |
42 | <div mat-dialog-actions fxLayout="row"> | 42 | <div mat-dialog-actions fxLayout="row"> |
43 | <span fxFlex></span> | 43 | <span fxFlex></span> |
44 | - <button mat-button mat-raised-button color="primary" | ||
45 | - type="submit" | ||
46 | - [disabled]="(isLoading$ | async) || dashboardCustomersFormGroup.invalid | ||
47 | - || !dashboardCustomersFormGroup.dirty"> | ||
48 | - {{ actionName | translate }} | ||
49 | - </button> | ||
50 | <button mat-button color="primary" | 44 | <button mat-button color="primary" |
51 | - style="margin-right: 20px;" | ||
52 | type="button" | 45 | type="button" |
53 | [disabled]="(isLoading$ | async)" | 46 | [disabled]="(isLoading$ | async)" |
54 | (click)="cancel()" cdkFocusInitial> | 47 | (click)="cancel()" cdkFocusInitial> |
55 | {{ 'action.cancel' | translate }} | 48 | {{ 'action.cancel' | translate }} |
56 | </button> | 49 | </button> |
50 | + <button mat-button mat-raised-button color="primary" | ||
51 | + type="submit" | ||
52 | + [disabled]="(isLoading$ | async) || dashboardCustomersFormGroup.invalid | ||
53 | + || !dashboardCustomersFormGroup.dirty"> | ||
54 | + {{ actionName | translate }} | ||
55 | + </button> | ||
57 | </div> | 56 | </div> |
58 | </form> | 57 | </form> |
@@ -52,16 +52,16 @@ | @@ -52,16 +52,16 @@ | ||
52 | </fieldset> | 52 | </fieldset> |
53 | </div> | 53 | </div> |
54 | <div mat-dialog-actions fxLayoutAlign="end center"> | 54 | <div mat-dialog-actions fxLayoutAlign="end center"> |
55 | - <button mat-raised-button color="primary" | ||
56 | - type="submit" | ||
57 | - [disabled]="(isLoading$ | async) || stateFormGroup.invalid || !stateFormGroup.dirty"> | ||
58 | - {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
59 | - </button> | ||
60 | <button mat-button color="primary" | 55 | <button mat-button color="primary" |
61 | type="button" | 56 | type="button" |
62 | [disabled]="(isLoading$ | async)" | 57 | [disabled]="(isLoading$ | async)" |
63 | (click)="cancel()" cdkFocusInitial> | 58 | (click)="cancel()" cdkFocusInitial> |
64 | {{ 'action.cancel' | translate }} | 59 | {{ 'action.cancel' | translate }} |
65 | </button> | 60 | </button> |
61 | + <button mat-raised-button color="primary" | ||
62 | + type="submit" | ||
63 | + [disabled]="(isLoading$ | async) || stateFormGroup.invalid || !stateFormGroup.dirty"> | ||
64 | + {{ (isAdd ? 'action.add' : 'action.save') | translate }} | ||
65 | + </button> | ||
66 | </div> | 66 | </div> |
67 | </form> | 67 | </form> |
@@ -136,16 +136,16 @@ | @@ -136,16 +136,16 @@ | ||
136 | </fieldset> | 136 | </fieldset> |
137 | </div> | 137 | </div> |
138 | <div mat-dialog-actions fxLayoutAlign="end center"> | 138 | <div mat-dialog-actions fxLayoutAlign="end center"> |
139 | - <button mat-raised-button color="primary" | ||
140 | - type="submit" | ||
141 | - [disabled]="(isLoading$ | async) || statesFormGroup.invalid || !statesFormGroup.dirty"> | ||
142 | - {{ 'action.save' | translate }} | ||
143 | - </button> | ||
144 | <button mat-button color="primary" | 139 | <button mat-button color="primary" |
145 | type="button" | 140 | type="button" |
146 | [disabled]="(isLoading$ | async)" | 141 | [disabled]="(isLoading$ | async)" |
147 | (click)="cancel()" cdkFocusInitial> | 142 | (click)="cancel()" cdkFocusInitial> |
148 | {{ 'action.cancel' | translate }} | 143 | {{ 'action.cancel' | translate }} |
149 | </button> | 144 | </button> |
145 | + <button mat-raised-button color="primary" | ||
146 | + type="submit" | ||
147 | + [disabled]="(isLoading$ | async) || statesFormGroup.invalid || !statesFormGroup.dirty"> | ||
148 | + {{ 'action.save' | translate }} | ||
149 | + </button> | ||
150 | </div> | 150 | </div> |
151 | </form> | 151 | </form> |
@@ -70,7 +70,7 @@ | @@ -70,7 +70,7 @@ | ||
70 | </div> | 70 | </div> |
71 | </div> | 71 | </div> |
72 | </mat-tab> | 72 | </mat-tab> |
73 | -<mat-tab *ngIf="entity" | 73 | +<mat-tab *ngIf="entity && !isEdit" |
74 | label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab"> | 74 | label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab"> |
75 | <tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table> | 75 | <tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table> |
76 | </mat-tab> | 76 | </mat-tab> |
@@ -36,17 +36,17 @@ | @@ -36,17 +36,17 @@ | ||
36 | </fieldset> | 36 | </fieldset> |
37 | </div> | 37 | </div> |
38 | <div mat-dialog-actions fxLayoutAlign="end center"> | 38 | <div mat-dialog-actions fxLayoutAlign="end center"> |
39 | - <button *ngIf="!isReadOnly" mat-raised-button color="primary" | ||
40 | - type="submit" | ||
41 | - [disabled]="(isLoading$ | async) || deviceCredentialsFormGroup.invalid | ||
42 | - || !deviceCredentialsFormGroup.dirty"> | ||
43 | - {{ 'action.save' | translate }} | ||
44 | - </button> | ||
45 | <button mat-button color="primary" | 39 | <button mat-button color="primary" |
46 | type="button" | 40 | type="button" |
47 | [disabled]="(isLoading$ | async)" | 41 | [disabled]="(isLoading$ | async)" |
48 | (click)="cancel()" cdkFocusInitial> | 42 | (click)="cancel()" cdkFocusInitial> |
49 | {{ (isReadOnly ? 'action.close' : 'action.cancel') | translate }} | 43 | {{ (isReadOnly ? 'action.close' : 'action.cancel') | translate }} |
50 | </button> | 44 | </button> |
45 | + <button *ngIf="!isReadOnly" mat-raised-button color="primary" | ||
46 | + type="submit" | ||
47 | + [disabled]="(isLoading$ | async) || deviceCredentialsFormGroup.invalid | ||
48 | + || !deviceCredentialsFormGroup.dirty"> | ||
49 | + {{ 'action.save' | translate }} | ||
50 | + </button> | ||
51 | </div> | 51 | </div> |
52 | </form> | 52 | </form> |
@@ -46,16 +46,16 @@ | @@ -46,16 +46,16 @@ | ||
46 | </mat-form-field> | 46 | </mat-form-field> |
47 | </div> | 47 | </div> |
48 | <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center"> | 48 | <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center"> |
49 | - <button mat-raised-button color="primary" | ||
50 | - type="submit" | ||
51 | - [disabled]="(isLoading$ | async) || changePassword.invalid"> | ||
52 | - {{ 'profile.change-password' | translate }} | ||
53 | - </button> | ||
54 | <button mat-button color="primary" | 49 | <button mat-button color="primary" |
55 | type="button" | 50 | type="button" |
56 | [disabled]="(isLoading$ | async)" | 51 | [disabled]="(isLoading$ | async)" |
57 | [mat-dialog-close]="false" cdkFocusInitial> | 52 | [mat-dialog-close]="false" cdkFocusInitial> |
58 | {{ 'action.cancel' | translate }} | 53 | {{ 'action.cancel' | translate }} |
59 | </button> | 54 | </button> |
55 | + <button mat-raised-button color="primary" | ||
56 | + type="submit" | ||
57 | + [disabled]="(isLoading$ | async) || changePassword.invalid"> | ||
58 | + {{ 'profile.change-password' | translate }} | ||
59 | + </button> | ||
60 | </div> | 60 | </div> |
61 | </form> | 61 | </form> |
@@ -40,16 +40,16 @@ | @@ -40,16 +40,16 @@ | ||
40 | </fieldset> | 40 | </fieldset> |
41 | </div> | 41 | </div> |
42 | <div mat-dialog-actions fxLayoutAlign="end center"> | 42 | <div mat-dialog-actions fxLayoutAlign="end center"> |
43 | - <button mat-raised-button color="primary" | ||
44 | - type="submit" | ||
45 | - [disabled]="(isLoading$ | async) || tbRuleNode.ruleNodeFormGroup.invalid || !tbRuleNode.ruleNodeFormGroup.dirty"> | ||
46 | - {{ 'action.add' | translate }} | ||
47 | - </button> | ||
48 | <button mat-button color="primary" | 43 | <button mat-button color="primary" |
49 | type="button" | 44 | type="button" |
50 | [disabled]="(isLoading$ | async)" | 45 | [disabled]="(isLoading$ | async)" |
51 | (click)="cancel()" cdkFocusInitial> | 46 | (click)="cancel()" cdkFocusInitial> |
52 | {{ 'action.cancel' | translate }} | 47 | {{ 'action.cancel' | translate }} |
53 | </button> | 48 | </button> |
49 | + <button mat-raised-button color="primary" | ||
50 | + type="submit" | ||
51 | + [disabled]="(isLoading$ | async) || tbRuleNode.ruleNodeFormGroup.invalid || !tbRuleNode.ruleNodeFormGroup.dirty"> | ||
52 | + {{ 'action.add' | translate }} | ||
53 | + </button> | ||
54 | </div> | 54 | </div> |
55 | </form> | 55 | </form> |
@@ -39,16 +39,16 @@ | @@ -39,16 +39,16 @@ | ||
39 | </fieldset> | 39 | </fieldset> |
40 | </div> | 40 | </div> |
41 | <div mat-dialog-actions fxLayoutAlign="end center"> | 41 | <div mat-dialog-actions fxLayoutAlign="end center"> |
42 | - <button mat-raised-button color="primary" | ||
43 | - type="submit" | ||
44 | - [disabled]="(isLoading$ | async) || ruleNodeLinkFormGroup.invalid || !ruleNodeLinkFormGroup.dirty"> | ||
45 | - {{ 'action.add' | translate }} | ||
46 | - </button> | ||
47 | <button mat-button color="primary" | 42 | <button mat-button color="primary" |
48 | type="button" | 43 | type="button" |
49 | [disabled]="(isLoading$ | async)" | 44 | [disabled]="(isLoading$ | async)" |
50 | (click)="cancel()" cdkFocusInitial> | 45 | (click)="cancel()" cdkFocusInitial> |
51 | {{ 'action.cancel' | translate }} | 46 | {{ 'action.cancel' | translate }} |
52 | </button> | 47 | </button> |
48 | + <button mat-raised-button color="primary" | ||
49 | + type="submit" | ||
50 | + [disabled]="(isLoading$ | async) || ruleNodeLinkFormGroup.invalid || !ruleNodeLinkFormGroup.dirty"> | ||
51 | + {{ 'action.add' | translate }} | ||
52 | + </button> | ||
53 | </div> | 53 | </div> |
54 | </form> | 54 | </form> |
@@ -41,11 +41,6 @@ | @@ -41,11 +41,6 @@ | ||
41 | </mat-form-field> | 41 | </mat-form-field> |
42 | </div> | 42 | </div> |
43 | <div mat-dialog-actions fxLayoutAlign="end center"> | 43 | <div mat-dialog-actions fxLayoutAlign="end center"> |
44 | - <button mat-raised-button color="primary" | ||
45 | - type="submit" | ||
46 | - [disabled]="(isLoading$ | async) || detailsForm.invalid || !detailsForm.dirty"> | ||
47 | - {{ 'action.add' | translate }} | ||
48 | - </button> | ||
49 | <button mat-button color="primary" | 44 | <button mat-button color="primary" |
50 | type="button" | 45 | type="button" |
51 | cdkFocusInitial | 46 | cdkFocusInitial |
@@ -53,5 +48,10 @@ | @@ -53,5 +48,10 @@ | ||
53 | (click)="cancel()"> | 48 | (click)="cancel()"> |
54 | {{ 'action.cancel' | translate }} | 49 | {{ 'action.cancel' | translate }} |
55 | </button> | 50 | </button> |
51 | + <button mat-raised-button color="primary" | ||
52 | + type="submit" | ||
53 | + [disabled]="(isLoading$ | async) || detailsForm.invalid || !detailsForm.dirty"> | ||
54 | + {{ 'action.add' | translate }} | ||
55 | + </button> | ||
56 | </div> | 56 | </div> |
57 | </form> | 57 | </form> |
@@ -46,17 +46,17 @@ | @@ -46,17 +46,17 @@ | ||
46 | </fieldset> | 46 | </fieldset> |
47 | </div> | 47 | </div> |
48 | <div mat-dialog-actions fxLayoutAlign="end center"> | 48 | <div mat-dialog-actions fxLayoutAlign="end center"> |
49 | - <button mat-raised-button color="primary" | ||
50 | - type="submit" | ||
51 | - [disabled]="(isLoading$ | async) || saveWidgetTypeAsFormGroup.invalid | ||
52 | - || !saveWidgetTypeAsFormGroup.dirty"> | ||
53 | - {{ 'action.saveAs' | translate }} | ||
54 | - </button> | ||
55 | <button mat-button color="primary" | 49 | <button mat-button color="primary" |
56 | type="button" | 50 | type="button" |
57 | [disabled]="(isLoading$ | async)" | 51 | [disabled]="(isLoading$ | async)" |
58 | (click)="cancel()" cdkFocusInitial> | 52 | (click)="cancel()" cdkFocusInitial> |
59 | {{ 'action.cancel' | translate }} | 53 | {{ 'action.cancel' | translate }} |
60 | </button> | 54 | </button> |
55 | + <button mat-raised-button color="primary" | ||
56 | + type="submit" | ||
57 | + [disabled]="(isLoading$ | async) || saveWidgetTypeAsFormGroup.invalid | ||
58 | + || !saveWidgetTypeAsFormGroup.dirty"> | ||
59 | + {{ 'action.saveAs' | translate }} | ||
60 | + </button> | ||
61 | </div> | 61 | </div> |
62 | </form> | 62 | </form> |
@@ -34,7 +34,6 @@ | @@ -34,7 +34,6 @@ | ||
34 | </button> | 34 | </button> |
35 | <button mat-button | 35 | <button mat-button |
36 | type="submit" | 36 | type="submit" |
37 | - style="margin-right: 20px;" | ||
38 | [disabled]="(isLoading$ | async) || colorPickerFormGroup.invalid || !colorPickerFormGroup.dirty"> | 37 | [disabled]="(isLoading$ | async) || colorPickerFormGroup.invalid || !colorPickerFormGroup.dirty"> |
39 | {{ 'action.select' | translate }} | 38 | {{ 'action.select' | translate }} |
40 | </button> | 39 | </button> |
@@ -41,17 +41,16 @@ | @@ -41,17 +41,16 @@ | ||
41 | </div> | 41 | </div> |
42 | <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center"> | 42 | <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center"> |
43 | <span fxFlex></span> | 43 | <span fxFlex></span> |
44 | - <button mat-button mat-raised-button color="primary" | ||
45 | - type="submit" | ||
46 | - [disabled]="(isLoading$ | async) || jsonFormGroup.invalid || !jsonFormGroup.dirty"> | ||
47 | - {{ 'action.save' | translate }} | ||
48 | - </button> | ||
49 | <button mat-button color="primary" | 44 | <button mat-button color="primary" |
50 | - style="margin-right: 20px;" | ||
51 | type="button" | 45 | type="button" |
52 | [disabled]="(isLoading$ | async)" | 46 | [disabled]="(isLoading$ | async)" |
53 | (click)="cancel()" cdkFocusInitial> | 47 | (click)="cancel()" cdkFocusInitial> |
54 | {{ 'action.cancel' | translate }} | 48 | {{ 'action.cancel' | translate }} |
55 | </button> | 49 | </button> |
50 | + <button mat-button mat-raised-button color="primary" | ||
51 | + type="submit" | ||
52 | + [disabled]="(isLoading$ | async) || jsonFormGroup.invalid || !jsonFormGroup.dirty"> | ||
53 | + {{ 'action.save' | translate }} | ||
54 | + </button> | ||
56 | </div> | 55 | </div> |
57 | </form> | 56 | </form> |
@@ -109,18 +109,17 @@ | @@ -109,18 +109,17 @@ | ||
109 | {{ 'rulenode.test' | translate }} | 109 | {{ 'rulenode.test' | translate }} |
110 | </button> | 110 | </button> |
111 | <span fxFlex></span> | 111 | <span fxFlex></span> |
112 | - <button mat-button mat-raised-button color="primary" | ||
113 | - type="submit" | ||
114 | - [disabled]="(isLoading$ | async) || nodeScriptTestFormGroup.get('script').invalid || !nodeScriptTestFormGroup.get('script').dirty"> | ||
115 | - {{ 'action.save' | translate }} | ||
116 | - </button> | ||
117 | <button mat-button color="primary" | 112 | <button mat-button color="primary" |
118 | - style="margin-right: 20px;" | ||
119 | type="button" | 113 | type="button" |
120 | cdkFocusInitial | 114 | cdkFocusInitial |
121 | [disabled]="(isLoading$ | async)" | 115 | [disabled]="(isLoading$ | async)" |
122 | (click)="cancel()"> | 116 | (click)="cancel()"> |
123 | {{ 'action.cancel' | translate }} | 117 | {{ 'action.cancel' | translate }} |
124 | </button> | 118 | </button> |
119 | + <button mat-button mat-raised-button color="primary" | ||
120 | + type="submit" | ||
121 | + [disabled]="(isLoading$ | async) || nodeScriptTestFormGroup.get('script').invalid || !nodeScriptTestFormGroup.get('script').dirty"> | ||
122 | + {{ 'action.save' | translate }} | ||
123 | + </button> | ||
125 | </div> | 124 | </div> |
126 | </form> | 125 | </form> |
@@ -140,19 +140,18 @@ | @@ -140,19 +140,18 @@ | ||
140 | </tb-timeinterval> | 140 | </tb-timeinterval> |
141 | </div> | 141 | </div> |
142 | <div fxLayout="row" class="tb-panel-actions" fxLayoutAlign="end center"> | 142 | <div fxLayout="row" class="tb-panel-actions" fxLayoutAlign="end center"> |
143 | + <button type="button" | ||
144 | + mat-button | ||
145 | + [disabled]="(isLoading$ | async)" | ||
146 | + (click)="cancel()"> | ||
147 | + {{ 'action.cancel' | translate }} | ||
148 | + </button> | ||
143 | <button type="submit" | 149 | <button type="submit" |
144 | mat-raised-button | 150 | mat-raised-button |
145 | color="primary" | 151 | color="primary" |
146 | [disabled]="(isLoading$ | async) || timewindowForm.invalid || !timewindowForm.dirty"> | 152 | [disabled]="(isLoading$ | async) || timewindowForm.invalid || !timewindowForm.dirty"> |
147 | {{ 'action.update' | translate }} | 153 | {{ 'action.update' | translate }} |
148 | </button> | 154 | </button> |
149 | - <button type="button" | ||
150 | - mat-button | ||
151 | - [disabled]="(isLoading$ | async)" | ||
152 | - (click)="cancel()" | ||
153 | - style="margin-right: 20px;"> | ||
154 | - {{ 'action.cancel' | translate }} | ||
155 | - </button> | ||
156 | </div> | 155 | </div> |
157 | </div> | 156 | </div> |
158 | </fieldset> | 157 | </fieldset> |
@@ -26,7 +26,7 @@ import { EntityInfoData } from '@shared/models/entity.models'; | @@ -26,7 +26,7 @@ import { EntityInfoData } from '@shared/models/entity.models'; | ||
26 | import { KeyFilter } from '@shared/models/query/query.models'; | 26 | import { KeyFilter } from '@shared/models/query/query.models'; |
27 | import { TimeUnit } from '@shared/models/time/time.models'; | 27 | import { TimeUnit } from '@shared/models/time/time.models'; |
28 | import * as _moment from 'moment-timezone'; | 28 | import * as _moment from 'moment-timezone'; |
29 | -import { AbstractControl, FormGroup } from '@angular/forms'; | 29 | +import { AbstractControl, FormGroup, ValidationErrors } from '@angular/forms'; |
30 | 30 | ||
31 | export enum DeviceProfileType { | 31 | export enum DeviceProfileType { |
32 | DEFAULT = 'DEFAULT' | 32 | DEFAULT = 'DEFAULT' |
@@ -87,7 +87,7 @@ export const deviceProvisionTypeTranslationMap = new Map<DeviceProvisionType, st | @@ -87,7 +87,7 @@ export const deviceProvisionTypeTranslationMap = new Map<DeviceProvisionType, st | ||
87 | [DeviceProvisionType.ALLOW_CREATE_NEW_DEVICES, 'device-profile.provision-strategy-created-new'], | 87 | [DeviceProvisionType.ALLOW_CREATE_NEW_DEVICES, 'device-profile.provision-strategy-created-new'], |
88 | [DeviceProvisionType.CHECK_PRE_PROVISIONED_DEVICES, 'device-profile.provision-strategy-check-pre-provisioned'] | 88 | [DeviceProvisionType.CHECK_PRE_PROVISIONED_DEVICES, 'device-profile.provision-strategy-check-pre-provisioned'] |
89 | ] | 89 | ] |
90 | -) | 90 | +); |
91 | 91 | ||
92 | export const deviceTransportTypeHintMap = new Map<DeviceTransportType, string>( | 92 | export const deviceTransportTypeHintMap = new Map<DeviceTransportType, string>( |
93 | [ | 93 | [ |
@@ -303,6 +303,18 @@ export interface AlarmRule { | @@ -303,6 +303,18 @@ export interface AlarmRule { | ||
303 | schedule?: AlarmSchedule; | 303 | schedule?: AlarmSchedule; |
304 | } | 304 | } |
305 | 305 | ||
306 | +export function alarmRuleValidator(control: AbstractControl): ValidationErrors | null { | ||
307 | + const alarmRule: AlarmRule = control.value; | ||
308 | + return alarmRuleValid(alarmRule) ? null : {alarmRule: true}; | ||
309 | +} | ||
310 | + | ||
311 | +function alarmRuleValid(alarmRule: AlarmRule): boolean { | ||
312 | + if (!alarmRule || !alarmRule.condition || !alarmRule.condition.condition || !alarmRule.condition.condition.length) { | ||
313 | + return false; | ||
314 | + } | ||
315 | + return true; | ||
316 | +} | ||
317 | + | ||
306 | export interface DeviceProfileAlarm { | 318 | export interface DeviceProfileAlarm { |
307 | id: string; | 319 | id: string; |
308 | alarmType: string; | 320 | alarmType: string; |
@@ -312,6 +324,34 @@ export interface DeviceProfileAlarm { | @@ -312,6 +324,34 @@ export interface DeviceProfileAlarm { | ||
312 | propagateRelationTypes?: Array<string>; | 324 | propagateRelationTypes?: Array<string>; |
313 | } | 325 | } |
314 | 326 | ||
327 | +export function deviceProfileAlarmValidator(control: AbstractControl): ValidationErrors | null { | ||
328 | + const deviceProfileAlarm: DeviceProfileAlarm = control.value; | ||
329 | + if (deviceProfileAlarm && deviceProfileAlarm.id && deviceProfileAlarm.alarmType && | ||
330 | + deviceProfileAlarm.createRules) { | ||
331 | + const severities = Object.keys(deviceProfileAlarm.createRules); | ||
332 | + if (severities.length) { | ||
333 | + let alarmRulesValid = true; | ||
334 | + for (const severity of severities) { | ||
335 | + const alarmRule = deviceProfileAlarm.createRules[severity]; | ||
336 | + if (!alarmRuleValid(alarmRule)) { | ||
337 | + alarmRulesValid = false; | ||
338 | + break; | ||
339 | + } | ||
340 | + } | ||
341 | + if (alarmRulesValid) { | ||
342 | + if (deviceProfileAlarm.clearRule && !alarmRuleValid(deviceProfileAlarm.clearRule)) { | ||
343 | + alarmRulesValid = false; | ||
344 | + } | ||
345 | + } | ||
346 | + if (alarmRulesValid) { | ||
347 | + return null; | ||
348 | + } | ||
349 | + } | ||
350 | + } | ||
351 | + return {deviceProfileAlarm: true}; | ||
352 | +} | ||
353 | + | ||
354 | + | ||
315 | export interface DeviceProfileData { | 355 | export interface DeviceProfileData { |
316 | configuration: DeviceProfileConfiguration; | 356 | configuration: DeviceProfileConfiguration; |
317 | transportConfiguration: DeviceProfileTransportConfiguration; | 357 | transportConfiguration: DeviceProfileTransportConfiguration; |
@@ -908,6 +908,7 @@ | @@ -908,6 +908,7 @@ | ||
908 | "create-alarm-pattern": "Create <b>{{alarmType}}</b> alarm", | 908 | "create-alarm-pattern": "Create <b>{{alarmType}}</b> alarm", |
909 | "create-alarm-rules": "Create alarm rules", | 909 | "create-alarm-rules": "Create alarm rules", |
910 | "no-create-alarm-rules": "No create conditions configured", | 910 | "no-create-alarm-rules": "No create conditions configured", |
911 | + "add-create-alarm-rule-prompt": "Please add create alarm rule", | ||
911 | "clear-alarm-rule": "Clear alarm rule", | 912 | "clear-alarm-rule": "Clear alarm rule", |
912 | "no-clear-alarm-rule": "No clear condition configured", | 913 | "no-clear-alarm-rule": "No clear condition configured", |
913 | "add-create-alarm-rule": "Add create condition", | 914 | "add-create-alarm-rule": "Add create condition", |
@@ -331,6 +331,9 @@ pre.tb-highlight { | @@ -331,6 +331,9 @@ pre.tb-highlight { | ||
331 | font-weight: 400; | 331 | font-weight: 400; |
332 | line-height: 18px; | 332 | line-height: 18px; |
333 | color: rgba(0, 0, 0, .38); | 333 | color: rgba(0, 0, 0, .38); |
334 | + &.required { | ||
335 | + color: rgb(221, 44, 0); | ||
336 | + } | ||
334 | } | 337 | } |
335 | 338 | ||
336 | .tb-fullscreen { | 339 | .tb-fullscreen { |