Commit 3d6b058b9dbaf485994bc68a98d6b9c71b9d0530
1 parent
65b7c139
Add widget to dashboard. CSV bulk import. User default place management.
Showing
63 changed files
with
2631 additions
and
510 deletions
Too many changes to show.
To preserve performance only 63 of 89 files are displayed.
@@ -5140,9 +5140,9 @@ | @@ -5140,9 +5140,9 @@ | ||
5140 | "dev": true | 5140 | "dev": true |
5141 | }, | 5141 | }, |
5142 | "handlebars": { | 5142 | "handlebars": { |
5143 | - "version": "4.4.3", | ||
5144 | - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.3.tgz", | ||
5145 | - "integrity": "sha512-B0W4A2U1ww3q7VVthTKfh+epHx+q4mCt6iK+zEAzbMBpWQAwxCeKxEGpj/1oQTpzPXDNSOG7hmG14TsISH50yw==", | 5143 | + "version": "4.5.1", |
5144 | + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", | ||
5145 | + "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", | ||
5146 | "dev": true, | 5146 | "dev": true, |
5147 | "requires": { | 5147 | "requires": { |
5148 | "neo-async": "^2.6.0", | 5148 | "neo-async": "^2.6.0", |
@@ -7411,6 +7411,16 @@ | @@ -7411,6 +7411,16 @@ | ||
7411 | "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-8.2.0.tgz", | 7411 | "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-8.2.0.tgz", |
7412 | "integrity": "sha512-rzR+cByjNG9M/UskU5vNoH7cUc6oM8STTDFKOZmnlX4ALOuM1+61CBjsNTGETWfo9a/h5mbGX02oh5/iNAa7vA==" | 7412 | "integrity": "sha512-rzR+cByjNG9M/UskU5vNoH7cUc6oM8STTDFKOZmnlX4ALOuM1+61CBjsNTGETWfo9a/h5mbGX02oh5/iNAa7vA==" |
7413 | }, | 7413 | }, |
7414 | + "ngx-hm-carousel": { | ||
7415 | + "version": "1.7.2", | ||
7416 | + "resolved": "https://registry.npmjs.org/ngx-hm-carousel/-/ngx-hm-carousel-1.7.2.tgz", | ||
7417 | + "integrity": "sha512-l53iWKO+brHPCgveqz9eBYvs0/YUp3EAIaxY30c361heMfegNI9yX/xDNXcwCZiKY80KKeT04Qqxos+EyZl/VQ==", | ||
7418 | + "requires": { | ||
7419 | + "hammerjs": "^2.0.8", | ||
7420 | + "resize-observer-polyfill": "^1.5.1", | ||
7421 | + "tslib": "^1.9.0" | ||
7422 | + } | ||
7423 | + }, | ||
7414 | "ngx-translate-messageformat-compiler": { | 7424 | "ngx-translate-messageformat-compiler": { |
7415 | "version": "4.5.0", | 7425 | "version": "4.5.0", |
7416 | "resolved": "https://registry.npmjs.org/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-4.5.0.tgz", | 7426 | "resolved": "https://registry.npmjs.org/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-4.5.0.tgz", |
@@ -10786,23 +10796,16 @@ | @@ -10786,23 +10796,16 @@ | ||
10786 | "dev": true | 10796 | "dev": true |
10787 | }, | 10797 | }, |
10788 | "uglify-js": { | 10798 | "uglify-js": { |
10789 | - "version": "3.6.2", | ||
10790 | - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.2.tgz", | ||
10791 | - "integrity": "sha512-+gh/xFte41GPrgSMJ/oJVq15zYmqr74pY9VoM69UzMzq9NFk4YDylclb1/bhEzZSaUQjbW5RvniHeq1cdtRYjw==", | 10799 | + "version": "3.6.8", |
10800 | + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.8.tgz", | ||
10801 | + "integrity": "sha512-XhHJ3S3ZyMwP8kY1Gkugqx3CJh2C3O0y8NPiSxtm1tyD/pktLAkFZsFGpuNfTZddKDQ/bbDBLAd2YyA1pbi8HQ==", | ||
10792 | "dev": true, | 10802 | "dev": true, |
10793 | "optional": true, | 10803 | "optional": true, |
10794 | "requires": { | 10804 | "requires": { |
10795 | - "commander": "2.20.0", | 10805 | + "commander": "~2.20.3", |
10796 | "source-map": "~0.6.1" | 10806 | "source-map": "~0.6.1" |
10797 | }, | 10807 | }, |
10798 | "dependencies": { | 10808 | "dependencies": { |
10799 | - "commander": { | ||
10800 | - "version": "2.20.0", | ||
10801 | - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", | ||
10802 | - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", | ||
10803 | - "dev": true, | ||
10804 | - "optional": true | ||
10805 | - }, | ||
10806 | "source-map": { | 10809 | "source-map": { |
10807 | "version": "0.6.1", | 10810 | "version": "0.6.1", |
10808 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", | 10811 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", |
@@ -59,6 +59,7 @@ | @@ -59,6 +59,7 @@ | ||
59 | "moment": "^2.24.0", | 59 | "moment": "^2.24.0", |
60 | "ngx-clipboard": "^12.2.0", | 60 | "ngx-clipboard": "^12.2.0", |
61 | "ngx-color-picker": "^8.2.0", | 61 | "ngx-color-picker": "^8.2.0", |
62 | + "ngx-hm-carousel": "^1.7.2", | ||
62 | "ngx-translate-messageformat-compiler": "^4.5.0", | 63 | "ngx-translate-messageformat-compiler": "^4.5.0", |
63 | "objectpath": "^1.2.2", | 64 | "objectpath": "^1.2.2", |
64 | "prop-types": "^15.7.2", | 65 | "prop-types": "^15.7.2", |
@@ -22,7 +22,8 @@ export enum AuthActionTypes { | @@ -22,7 +22,8 @@ export enum AuthActionTypes { | ||
22 | AUTHENTICATED = '[Auth] Authenticated', | 22 | AUTHENTICATED = '[Auth] Authenticated', |
23 | UNAUTHENTICATED = '[Auth] Unauthenticated', | 23 | UNAUTHENTICATED = '[Auth] Unauthenticated', |
24 | LOAD_USER = '[Auth] Load User', | 24 | LOAD_USER = '[Auth] Load User', |
25 | - UPDATE_USER_DETAILS = '[Auth] Update User Details' | 25 | + UPDATE_USER_DETAILS = '[Auth] Update User Details', |
26 | + UPDATE_LAST_PUBLIC_DASHBOARD_ID = '[Auth] Update Last Public Dashboard Id' | ||
26 | } | 27 | } |
27 | 28 | ||
28 | export class ActionAuthAuthenticated implements Action { | 29 | export class ActionAuthAuthenticated implements Action { |
@@ -47,4 +48,11 @@ export class ActionAuthUpdateUserDetails implements Action { | @@ -47,4 +48,11 @@ export class ActionAuthUpdateUserDetails implements Action { | ||
47 | constructor(readonly payload: { userDetails: User }) {} | 48 | constructor(readonly payload: { userDetails: User }) {} |
48 | } | 49 | } |
49 | 50 | ||
50 | -export type AuthActions = ActionAuthAuthenticated | ActionAuthUnauthenticated | ActionAuthLoadUser | ActionAuthUpdateUserDetails; | 51 | +export class ActionAuthUpdateLastPublicDashboardId implements Action { |
52 | + readonly type = AuthActionTypes.UPDATE_LAST_PUBLIC_DASHBOARD_ID; | ||
53 | + | ||
54 | + constructor(readonly payload: { lastPublicDashboardId: string }) {} | ||
55 | +} | ||
56 | + | ||
57 | +export type AuthActions = ActionAuthAuthenticated | ActionAuthUnauthenticated | | ||
58 | + ActionAuthLoadUser | ActionAuthUpdateUserDetails | ActionAuthUpdateLastPublicDashboardId; |
@@ -20,6 +20,8 @@ export interface AuthPayload { | @@ -20,6 +20,8 @@ export interface AuthPayload { | ||
20 | authUser: AuthUser; | 20 | authUser: AuthUser; |
21 | userDetails: User; | 21 | userDetails: User; |
22 | userTokenAccessEnabled: boolean; | 22 | userTokenAccessEnabled: boolean; |
23 | + allowedDashboardIds: string[]; | ||
24 | + forceFullscreen: boolean; | ||
23 | } | 25 | } |
24 | 26 | ||
25 | export interface AuthState { | 27 | export interface AuthState { |
@@ -28,4 +30,7 @@ export interface AuthState { | @@ -28,4 +30,7 @@ export interface AuthState { | ||
28 | authUser: AuthUser; | 30 | authUser: AuthUser; |
29 | userDetails: User; | 31 | userDetails: User; |
30 | userTokenAccessEnabled: boolean; | 32 | userTokenAccessEnabled: boolean; |
33 | + allowedDashboardIds: string[]; | ||
34 | + forceFullscreen: boolean; | ||
35 | + lastPublicDashboardId: string; | ||
31 | } | 36 | } |
@@ -20,12 +20,15 @@ import { AuthActions, AuthActionTypes } from './auth.actions'; | @@ -20,12 +20,15 @@ import { AuthActions, AuthActionTypes } from './auth.actions'; | ||
20 | const emptyUserAuthState: AuthPayload = { | 20 | const emptyUserAuthState: AuthPayload = { |
21 | authUser: null, | 21 | authUser: null, |
22 | userDetails: null, | 22 | userDetails: null, |
23 | - userTokenAccessEnabled: false | 23 | + userTokenAccessEnabled: false, |
24 | + forceFullscreen: false, | ||
25 | + allowedDashboardIds: [] | ||
24 | }; | 26 | }; |
25 | 27 | ||
26 | export const initialState: AuthState = { | 28 | export const initialState: AuthState = { |
27 | isAuthenticated: false, | 29 | isAuthenticated: false, |
28 | isUserLoaded: false, | 30 | isUserLoaded: false, |
31 | + lastPublicDashboardId: null, | ||
29 | ...emptyUserAuthState | 32 | ...emptyUserAuthState |
30 | }; | 33 | }; |
31 | 34 | ||
@@ -47,6 +50,9 @@ export function authReducer( | @@ -47,6 +50,9 @@ export function authReducer( | ||
47 | case AuthActionTypes.UPDATE_USER_DETAILS: | 50 | case AuthActionTypes.UPDATE_USER_DETAILS: |
48 | return { ...state, ...action.payload}; | 51 | return { ...state, ...action.payload}; |
49 | 52 | ||
53 | + case AuthActionTypes.UPDATE_LAST_PUBLIC_DASHBOARD_ID: | ||
54 | + return { ...state, ...action.payload}; | ||
55 | + | ||
50 | default: | 56 | default: |
51 | return state; | 57 | return state; |
52 | } | 58 | } |
@@ -14,36 +14,41 @@ | @@ -14,36 +14,41 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import {Injectable, NgZone} from '@angular/core'; | ||
18 | -import {JwtHelperService} from '@auth0/angular-jwt'; | ||
19 | -import {HttpClient} from '@angular/common/http'; | ||
20 | - | ||
21 | -import {combineLatest, forkJoin, Observable, of} from 'rxjs'; | ||
22 | -import {distinctUntilChanged, filter, map, skip, tap} from 'rxjs/operators'; | ||
23 | - | ||
24 | -import {LoginRequest, LoginResponse} from '../../shared/models/login.models'; | ||
25 | -import {ActivatedRoute, Router, UrlTree} from '@angular/router'; | ||
26 | -import {defaultHttpOptions} from '../http/http-utils'; | ||
27 | -import {ReplaySubject} from 'rxjs/internal/ReplaySubject'; | ||
28 | -import {UserService} from '../http/user.service'; | ||
29 | -import {select, Store} from '@ngrx/store'; | ||
30 | -import {AppState} from '../core.state'; | ||
31 | -import {ActionAuthAuthenticated, ActionAuthLoadUser, ActionAuthUnauthenticated} from './auth.actions'; | ||
32 | -import {getCurrentAuthUser, selectIsAuthenticated, selectIsUserLoaded} from './auth.selectors'; | ||
33 | -import {Authority} from '../../shared/models/authority.enum'; | ||
34 | -import {ActionSettingsChangeLanguage} from '@app/core/settings/settings.actions'; | ||
35 | -import {AuthPayload} from '@core/auth/auth.models'; | ||
36 | -import {TranslateService} from '@ngx-translate/core'; | ||
37 | -import {AuthUser} from '@shared/models/user.model'; | ||
38 | -import {TimeService} from '@core/services/time.service'; | 17 | +import { Injectable, NgZone } from '@angular/core'; |
18 | +import { JwtHelperService } from '@auth0/angular-jwt'; | ||
19 | +import { HttpClient } from '@angular/common/http'; | ||
20 | + | ||
21 | +import { combineLatest, forkJoin, Observable, of, throwError } from 'rxjs'; | ||
22 | +import { catchError, distinctUntilChanged, filter, map, mergeMap, skip, tap } from 'rxjs/operators'; | ||
23 | + | ||
24 | +import { LoginRequest, LoginResponse, PublicLoginRequest } from '../../shared/models/login.models'; | ||
25 | +import { ActivatedRoute, Router, UrlTree } from '@angular/router'; | ||
26 | +import { defaultHttpOptions } from '../http/http-utils'; | ||
27 | +import { ReplaySubject } from 'rxjs/internal/ReplaySubject'; | ||
28 | +import { UserService } from '../http/user.service'; | ||
29 | +import { select, Store } from '@ngrx/store'; | ||
30 | +import { AppState } from '../core.state'; | ||
31 | +import { ActionAuthAuthenticated, ActionAuthLoadUser, ActionAuthUnauthenticated } from './auth.actions'; | ||
32 | +import { getCurrentAuthState, getCurrentAuthUser, selectIsAuthenticated, selectIsUserLoaded } from './auth.selectors'; | ||
33 | +import { Authority } from '../../shared/models/authority.enum'; | ||
34 | +import { ActionSettingsChangeLanguage } from '@app/core/settings/settings.actions'; | ||
35 | +import { AuthPayload, AuthState } from '@core/auth/auth.models'; | ||
36 | +import { TranslateService } from '@ngx-translate/core'; | ||
37 | +import { AuthUser } from '@shared/models/user.model'; | ||
38 | +import { TimeService } from '@core/services/time.service'; | ||
39 | +import { UtilsService } from '@core/services/utils.service'; | ||
40 | +import { DashboardService } from '@core/http/dashboard.service'; | ||
41 | +import { PageLink } from '@shared/models/page/page-link'; | ||
42 | +import { DashboardInfo } from '@shared/models/dashboard.models'; | ||
43 | +import { PageData } from '@app/shared/models/page/page-data'; | ||
44 | +import { AdminService } from '@core/http/admin.service'; | ||
45 | +import { ActionNotificationShow } from '@core/notification/notification.actions'; | ||
39 | 46 | ||
40 | @Injectable({ | 47 | @Injectable({ |
41 | providedIn: 'root' | 48 | providedIn: 'root' |
42 | }) | 49 | }) |
43 | export class AuthService { | 50 | export class AuthService { |
44 | 51 | ||
45 | - forceFullscreen = false; // TODO: | ||
46 | - | ||
47 | constructor( | 52 | constructor( |
48 | private store: Store<AppState>, | 53 | private store: Store<AppState>, |
49 | private http: HttpClient, | 54 | private http: HttpClient, |
@@ -52,6 +57,9 @@ export class AuthService { | @@ -52,6 +57,9 @@ export class AuthService { | ||
52 | private router: Router, | 57 | private router: Router, |
53 | private route: ActivatedRoute, | 58 | private route: ActivatedRoute, |
54 | private zone: NgZone, | 59 | private zone: NgZone, |
60 | + private utils: UtilsService, | ||
61 | + private dashboardService: DashboardService, | ||
62 | + private adminService: AdminService, | ||
55 | private translate: TranslateService | 63 | private translate: TranslateService |
56 | ) { | 64 | ) { |
57 | combineLatest( | 65 | combineLatest( |
@@ -119,6 +127,13 @@ export class AuthService { | @@ -119,6 +127,13 @@ export class AuthService { | ||
119 | )); | 127 | )); |
120 | } | 128 | } |
121 | 129 | ||
130 | + public publicLogin(publicId: string): Observable<LoginResponse> { | ||
131 | + const publicLoginRequest: PublicLoginRequest = { | ||
132 | + publicId | ||
133 | + }; | ||
134 | + return this.http.post<LoginResponse>('/api/auth/login/public', publicLoginRequest, defaultHttpOptions()); | ||
135 | + } | ||
136 | + | ||
122 | public sendResetPasswordLink(email: string) { | 137 | public sendResetPasswordLink(email: string) { |
123 | return this.http.post('/api/noauth/resetPasswordByEmail', | 138 | return this.http.post('/api/noauth/resetPasswordByEmail', |
124 | {email}, defaultHttpOptions()); | 139 | {email}, defaultHttpOptions()); |
@@ -182,39 +197,118 @@ export class AuthService { | @@ -182,39 +197,118 @@ export class AuthService { | ||
182 | } | 197 | } |
183 | 198 | ||
184 | public gotoDefaultPlace(isAuthenticated: boolean) { | 199 | public gotoDefaultPlace(isAuthenticated: boolean) { |
185 | - const url = this.defaultUrl(isAuthenticated); | 200 | + const authState = getCurrentAuthState(this.store); |
201 | + const url = this.defaultUrl(isAuthenticated, authState); | ||
186 | this.zone.run(() => { | 202 | this.zone.run(() => { |
187 | this.router.navigateByUrl(url); | 203 | this.router.navigateByUrl(url); |
188 | }); | 204 | }); |
189 | } | 205 | } |
190 | 206 | ||
191 | - public defaultUrl(isAuthenticated: boolean): UrlTree { | ||
192 | - if (isAuthenticated) { | ||
193 | - if (this.redirectUrl) { | ||
194 | - const redirectUrl = this.redirectUrl; | ||
195 | - this.redirectUrl = null; | ||
196 | - return this.router.parseUrl(redirectUrl); | ||
197 | - } else { | ||
198 | - | ||
199 | - // TODO: | 207 | + private forceDefaultPlace(authState?: AuthState, path?: string, params?: any): boolean { |
208 | + if (authState && authState.authUser) { | ||
209 | + if (authState.authUser.authority === Authority.TENANT_ADMIN || authState.authUser.authority === Authority.CUSTOMER_USER) { | ||
210 | + if ((this.userHasDefaultDashboard(authState) && authState.forceFullscreen) || authState.authUser.isPublic) { | ||
211 | + if (path === 'profile') { | ||
212 | + if (this.userHasProfile(authState.authUser)) { | ||
213 | + return false; | ||
214 | + } else { | ||
215 | + return true; | ||
216 | + } | ||
217 | + } else if (path.startsWith('dashboard.') || path.startsWith('dashboards.') && | ||
218 | + authState.allowedDashboardIds.indexOf(params.dashboardId) > -1) { | ||
219 | + return false; | ||
220 | + } else { | ||
221 | + return true; | ||
222 | + } | ||
223 | + } | ||
224 | + } | ||
225 | + } | ||
226 | + return false; | ||
227 | + } | ||
200 | 228 | ||
201 | - return this.router.parseUrl('home'); | 229 | + public defaultUrl(isAuthenticated: boolean, authState?: AuthState, path?: string, params?: any): UrlTree { |
230 | + let result: UrlTree = null; | ||
231 | + if (isAuthenticated) { | ||
232 | + if (!path || path === 'login' || this.forceDefaultPlace(authState, path, params)) { | ||
233 | + if (this.redirectUrl) { | ||
234 | + const redirectUrl = this.redirectUrl; | ||
235 | + this.redirectUrl = null; | ||
236 | + result = this.router.parseUrl(redirectUrl); | ||
237 | + } else { | ||
238 | + result = this.router.parseUrl('home'); | ||
239 | + } | ||
240 | + if (authState.authUser.authority === Authority.TENANT_ADMIN || authState.authUser.authority === Authority.CUSTOMER_USER) { | ||
241 | + if (this.userHasDefaultDashboard(authState)) { | ||
242 | + const dashboardId = authState.userDetails.additionalInfo.defaultDashboardId; | ||
243 | + if (authState.forceFullscreen) { | ||
244 | + result = this.router.parseUrl(`dashboard/${dashboardId}`); | ||
245 | + } else { | ||
246 | + result = this.router.parseUrl(`dashboards/${dashboardId}`); | ||
247 | + } | ||
248 | + } else if (authState.authUser.isPublic) { | ||
249 | + result = this.router.parseUrl(`dashboard/${authState.lastPublicDashboardId}`); | ||
250 | + } | ||
251 | + } else if (authState.authUser.authority === Authority.SYS_ADMIN) { | ||
252 | + this.adminService.checkUpdates().subscribe((updateMessage) => { | ||
253 | + if (updateMessage && updateMessage.updateAvailable) { | ||
254 | + this.store.dispatch(new ActionNotificationShow( | ||
255 | + {message: updateMessage.message, | ||
256 | + type: 'info', | ||
257 | + verticalPosition: 'bottom', | ||
258 | + horizontalPosition: 'right'})); | ||
259 | + } | ||
260 | + }); | ||
261 | + } | ||
202 | } | 262 | } |
203 | } else { | 263 | } else { |
204 | - return this.router.parseUrl('login'); | 264 | + result = this.router.parseUrl('login'); |
205 | } | 265 | } |
266 | + return result; | ||
206 | } | 267 | } |
207 | 268 | ||
208 | private loadUser(doTokenRefresh): Observable<AuthPayload> { | 269 | private loadUser(doTokenRefresh): Observable<AuthPayload> { |
209 | const authUser = getCurrentAuthUser(this.store); | 270 | const authUser = getCurrentAuthUser(this.store); |
210 | if (!authUser) { | 271 | if (!authUser) { |
272 | + const publicId = this.utils.getQueryParam('publicId'); | ||
273 | + const accessToken = this.utils.getQueryParam('accessToken'); | ||
274 | + const refreshToken = this.utils.getQueryParam('refreshToken'); | ||
275 | + if (publicId) { | ||
276 | + return this.publicLogin(publicId).pipe( | ||
277 | + mergeMap((response) => { | ||
278 | + this.updateAndValidateToken(response.token, 'jwt_token', false); | ||
279 | + this.updateAndValidateToken(response.refreshToken, 'refresh_token', false); | ||
280 | + return this.procceedJwtTokenValidate(); | ||
281 | + }), | ||
282 | + catchError((err) => { | ||
283 | + this.utils.updateQueryParam('publicId', null); | ||
284 | + throw Error(); | ||
285 | + }) | ||
286 | + ); | ||
287 | + } else if (accessToken) { | ||
288 | + this.utils.updateQueryParam('accessToken', null); | ||
289 | + if (refreshToken) { | ||
290 | + this.utils.updateQueryParam('refreshToken', null); | ||
291 | + } | ||
292 | + try { | ||
293 | + this.updateAndValidateToken(accessToken, 'jwt_token', false); | ||
294 | + if (refreshToken) { | ||
295 | + this.updateAndValidateToken(refreshToken, 'refresh_token', false); | ||
296 | + } else { | ||
297 | + localStorage.removeItem('refresh_token'); | ||
298 | + localStorage.removeItem('refresh_token_expiration'); | ||
299 | + } | ||
300 | + } catch (e) { | ||
301 | + return throwError(e); | ||
302 | + } | ||
303 | + return this.procceedJwtTokenValidate(); | ||
304 | + } | ||
211 | return this.procceedJwtTokenValidate(doTokenRefresh); | 305 | return this.procceedJwtTokenValidate(doTokenRefresh); |
212 | } else { | 306 | } else { |
213 | return of({} as AuthPayload); | 307 | return of({} as AuthPayload); |
214 | } | 308 | } |
215 | } | 309 | } |
216 | 310 | ||
217 | - private procceedJwtTokenValidate(doTokenRefresh: boolean): Observable<AuthPayload> { | 311 | + private procceedJwtTokenValidate(doTokenRefresh?: boolean): Observable<AuthPayload> { |
218 | const loadUserSubject = new ReplaySubject<AuthPayload>(); | 312 | const loadUserSubject = new ReplaySubject<AuthPayload>(); |
219 | this.validateJwtToken(doTokenRefresh).subscribe( | 313 | this.validateJwtToken(doTokenRefresh).subscribe( |
220 | () => { | 314 | () => { |
@@ -226,18 +320,31 @@ export class AuthService { | @@ -226,18 +320,31 @@ export class AuthService { | ||
226 | } else if (authPayload.authUser) { | 320 | } else if (authPayload.authUser) { |
227 | authPayload.authUser.authority = Authority.ANONYMOUS; | 321 | authPayload.authUser.authority = Authority.ANONYMOUS; |
228 | } | 322 | } |
229 | - const sysParamsObservable = this.loadSystemParams(authPayload.authUser); | ||
230 | if (authPayload.authUser.isPublic) { | 323 | if (authPayload.authUser.isPublic) { |
231 | - | ||
232 | - // TODO: | ||
233 | - | 324 | + authPayload.forceFullscreen = true; |
325 | + } | ||
326 | + if (authPayload.authUser.isPublic) { | ||
327 | + this.loadSystemParams(authPayload).subscribe( | ||
328 | + (sysParams) => { | ||
329 | + authPayload = {...authPayload, ...sysParams}; | ||
330 | + loadUserSubject.next(authPayload); | ||
331 | + loadUserSubject.complete(); | ||
332 | + }, | ||
333 | + (err) => { | ||
334 | + loadUserSubject.error(err); | ||
335 | + } | ||
336 | + ); | ||
234 | } else if (authPayload.authUser.userId) { | 337 | } else if (authPayload.authUser.userId) { |
235 | this.userService.getUser(authPayload.authUser.userId).subscribe( | 338 | this.userService.getUser(authPayload.authUser.userId).subscribe( |
236 | (user) => { | 339 | (user) => { |
237 | - sysParamsObservable.subscribe( | 340 | + authPayload.userDetails = user; |
341 | + authPayload.forceFullscreen = false; | ||
342 | + if (this.userForceFullscreen(authPayload)) { | ||
343 | + authPayload.forceFullscreen = true; | ||
344 | + } | ||
345 | + this.loadSystemParams(authPayload).subscribe( | ||
238 | (sysParams) => { | 346 | (sysParams) => { |
239 | authPayload = {...authPayload, ...sysParams}; | 347 | authPayload = {...authPayload, ...sysParams}; |
240 | - authPayload.userDetails = user; | ||
241 | let userLang; | 348 | let userLang; |
242 | if (authPayload.userDetails.additionalInfo && authPayload.userDetails.additionalInfo.lang) { | 349 | if (authPayload.userDetails.additionalInfo && authPayload.userDetails.additionalInfo.lang) { |
243 | userLang = authPayload.userDetails.additionalInfo.lang; | 350 | userLang = authPayload.userDetails.additionalInfo.lang; |
@@ -278,13 +385,15 @@ export class AuthService { | @@ -278,13 +385,15 @@ export class AuthService { | ||
278 | } | 385 | } |
279 | } | 386 | } |
280 | 387 | ||
281 | - private loadSystemParams(authUser: AuthUser): Observable<any> { | ||
282 | - const sources: Array<Observable<any>> = [this.loadIsUserTokenAccessEnabled(authUser), | 388 | + private loadSystemParams(authPayload: AuthPayload): Observable<any> { |
389 | + const sources: Array<Observable<any>> = [this.loadIsUserTokenAccessEnabled(authPayload.authUser), | ||
390 | + this.fetchAllowedDashboardIds(authPayload), | ||
283 | this.timeService.loadMaxDatapointsLimit()]; | 391 | this.timeService.loadMaxDatapointsLimit()]; |
284 | return forkJoin(sources) | 392 | return forkJoin(sources) |
285 | .pipe(map((data) => { | 393 | .pipe(map((data) => { |
286 | const userTokenAccessEnabled: boolean = data[0]; | 394 | const userTokenAccessEnabled: boolean = data[0]; |
287 | - return {userTokenAccessEnabled}; | 395 | + const allowedDashboardIds: string[] = data[1]; |
396 | + return {userTokenAccessEnabled, allowedDashboardIds}; | ||
288 | })); | 397 | })); |
289 | } | 398 | } |
290 | 399 | ||
@@ -369,9 +478,20 @@ export class AuthService { | @@ -369,9 +478,20 @@ export class AuthService { | ||
369 | } | 478 | } |
370 | ); | 479 | ); |
371 | } else { | 480 | } else { |
372 | - this.loadUser(false); | 481 | + this.loadUser(false).subscribe(); |
482 | + } | ||
483 | + } | ||
484 | + } | ||
485 | + | ||
486 | + public parsePublicId(): string { | ||
487 | + const token = AuthService.getJwtToken(); | ||
488 | + if (token) { | ||
489 | + const tokenData = this.jwtHelper.decodeToken(token); | ||
490 | + if (tokenData && tokenData.isPublic) { | ||
491 | + return tokenData.sub; | ||
373 | } | 492 | } |
374 | } | 493 | } |
494 | + return null; | ||
375 | } | 495 | } |
376 | 496 | ||
377 | private notifyUnauthenticated() { | 497 | private notifyUnauthenticated() { |
@@ -409,4 +529,44 @@ export class AuthService { | @@ -409,4 +529,44 @@ export class AuthService { | ||
409 | this.setUserFromJwtToken(null, null, true); | 529 | this.setUserFromJwtToken(null, null, true); |
410 | } | 530 | } |
411 | 531 | ||
532 | + private userForceFullscreen(authPayload: AuthPayload): boolean { | ||
533 | + return (authPayload.authUser && authPayload.authUser.isPublic) || | ||
534 | + (authPayload.userDetails && authPayload.userDetails.additionalInfo && | ||
535 | + authPayload.userDetails.additionalInfo.defaultDashboardFullscreen && | ||
536 | + authPayload.userDetails.additionalInfo.defaultDashboardFullscreen === true); | ||
537 | + } | ||
538 | + | ||
539 | + private userHasProfile(authUser: AuthUser): boolean { | ||
540 | + return authUser && !authUser.isPublic; | ||
541 | + } | ||
542 | + | ||
543 | + private userHasDefaultDashboard(authState: AuthState): boolean { | ||
544 | + if (authState && authState.userDetails && authState.userDetails.additionalInfo | ||
545 | + && authState.userDetails.additionalInfo.defaultDashboardId) { | ||
546 | + return true; | ||
547 | + } else { | ||
548 | + return false; | ||
549 | + } | ||
550 | + } | ||
551 | + | ||
552 | + private fetchAllowedDashboardIds(authPayload: AuthPayload): Observable<string[]> { | ||
553 | + if (authPayload.forceFullscreen && (authPayload.authUser.authority === Authority.TENANT_ADMIN || | ||
554 | + authPayload.authUser.authority === Authority.CUSTOMER_USER)) { | ||
555 | + const pageLink = new PageLink(100); | ||
556 | + let fetchDashboardsObservable: Observable<PageData<DashboardInfo>>; | ||
557 | + if (authPayload.authUser.authority === Authority.TENANT_ADMIN) { | ||
558 | + fetchDashboardsObservable = this.dashboardService.getTenantDashboards(pageLink); | ||
559 | + } else { | ||
560 | + fetchDashboardsObservable = this.dashboardService.getCustomerDashboards(authPayload.authUser.customerId, pageLink); | ||
561 | + } | ||
562 | + return fetchDashboardsObservable.pipe( | ||
563 | + map((result) => { | ||
564 | + const dashboards = result.data; | ||
565 | + return dashboards.map(dashboard => dashboard.id.id); | ||
566 | + }) | ||
567 | + ); | ||
568 | + } else { | ||
569 | + return of([]); | ||
570 | + } | ||
571 | + } | ||
412 | } | 572 | } |
@@ -32,6 +32,7 @@ import { enterZone } from '@core/operator/enterZone'; | @@ -32,6 +32,7 @@ import { enterZone } from '@core/operator/enterZone'; | ||
32 | import { Authority } from '@shared/models/authority.enum'; | 32 | import { Authority } from '@shared/models/authority.enum'; |
33 | import { DialogService } from '@core/services/dialog.service'; | 33 | import { DialogService } from '@core/services/dialog.service'; |
34 | import { TranslateService } from '@ngx-translate/core'; | 34 | import { TranslateService } from '@ngx-translate/core'; |
35 | +import { UtilsService } from '@core/services/utils.service'; | ||
35 | 36 | ||
36 | @Injectable({ | 37 | @Injectable({ |
37 | providedIn: 'root' | 38 | providedIn: 'root' |
@@ -41,6 +42,7 @@ export class AuthGuard implements CanActivate, CanActivateChild { | @@ -41,6 +42,7 @@ export class AuthGuard implements CanActivate, CanActivateChild { | ||
41 | constructor(private store: Store<AppState>, | 42 | constructor(private store: Store<AppState>, |
42 | private authService: AuthService, | 43 | private authService: AuthService, |
43 | private dialogService: DialogService, | 44 | private dialogService: DialogService, |
45 | + private utils: UtilsService, | ||
44 | private translate: TranslateService, | 46 | private translate: TranslateService, |
45 | private zone: NgZone) {} | 47 | private zone: NgZone) {} |
46 | 48 | ||
@@ -61,14 +63,28 @@ export class AuthGuard implements CanActivate, CanActivateChild { | @@ -61,14 +63,28 @@ export class AuthGuard implements CanActivate, CanActivateChild { | ||
61 | const url: string = state.url; | 63 | const url: string = state.url; |
62 | 64 | ||
63 | let lastChild = state.root; | 65 | let lastChild = state.root; |
66 | + const urlSegments: string[] = []; | ||
67 | + if (lastChild.url) { | ||
68 | + urlSegments.push(...lastChild.url.map(segment => segment.path)); | ||
69 | + } | ||
64 | while (lastChild.children.length) { | 70 | while (lastChild.children.length) { |
65 | lastChild = lastChild.children[0]; | 71 | lastChild = lastChild.children[0]; |
72 | + if (lastChild.url) { | ||
73 | + urlSegments.push(...lastChild.url.map(segment => segment.path)); | ||
74 | + } | ||
66 | } | 75 | } |
76 | + const path = urlSegments.join('.'); | ||
77 | + const publicId = this.utils.getQueryParam('publicId'); | ||
67 | const data = lastChild.data || {}; | 78 | const data = lastChild.data || {}; |
79 | + const params = lastChild.params || {}; | ||
68 | const isPublic = data.module === 'public'; | 80 | const isPublic = data.module === 'public'; |
69 | 81 | ||
70 | if (!authState.isAuthenticated) { | 82 | if (!authState.isAuthenticated) { |
71 | - if (!isPublic) { | 83 | + if (publicId && publicId.length > 0) { |
84 | + this.authService.setUserFromJwtToken(null, null, false); | ||
85 | + this.authService.reloadUser(); | ||
86 | + return false; | ||
87 | + } else if (!isPublic) { | ||
72 | this.authService.redirectUrl = url; | 88 | this.authService.redirectUrl = url; |
73 | // this.authService.gotoDefaultPlace(false); | 89 | // this.authService.gotoDefaultPlace(false); |
74 | return this.authService.defaultUrl(false); | 90 | return this.authService.defaultUrl(false); |
@@ -76,9 +92,21 @@ export class AuthGuard implements CanActivate, CanActivateChild { | @@ -76,9 +92,21 @@ export class AuthGuard implements CanActivate, CanActivateChild { | ||
76 | return true; | 92 | return true; |
77 | } | 93 | } |
78 | } else { | 94 | } else { |
79 | - if (url === '/login') { | 95 | + if (authState.authUser.isPublic) { |
96 | + if (this.authService.parsePublicId() !== publicId) { | ||
97 | + if (publicId && publicId.length > 0) { | ||
98 | + this.authService.setUserFromJwtToken(null, null, false); | ||
99 | + this.authService.reloadUser(); | ||
100 | + } else { | ||
101 | + this.authService.logout(); | ||
102 | + } | ||
103 | + return false; | ||
104 | + } | ||
105 | + } | ||
106 | + const defaultUrl = this.authService.defaultUrl(true, authState, path, params); | ||
107 | + if (defaultUrl) { | ||
80 | // this.authService.gotoDefaultPlace(true); | 108 | // this.authService.gotoDefaultPlace(true); |
81 | - return this.authService.defaultUrl(true); | 109 | + return defaultUrl; |
82 | } else { | 110 | } else { |
83 | const authority = Authority[authState.authUser.authority]; | 111 | const authority = Authority[authState.authUser.authority]; |
84 | if (data.auth && data.auth.indexOf(authority) === -1) { | 112 | if (data.auth && data.auth.indexOf(authority) === -1) { |
@@ -15,10 +15,10 @@ | @@ -15,10 +15,10 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable } from 'rxjs/index'; | 19 | import { Observable } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | -import {AdminSettings, MailServerSettings, SecuritySettings} from '@shared/models/settings.models'; | 21 | +import { AdminSettings, MailServerSettings, SecuritySettings, UpdateMessage } from '@shared/models/settings.models'; |
22 | 22 | ||
23 | @Injectable({ | 23 | @Injectable({ |
24 | providedIn: 'root' | 24 | providedIn: 'root' |
@@ -29,27 +29,31 @@ export class AdminService { | @@ -29,27 +29,31 @@ export class AdminService { | ||
29 | private http: HttpClient | 29 | private http: HttpClient |
30 | ) { } | 30 | ) { } |
31 | 31 | ||
32 | - public getAdminSettings<T>(key: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<AdminSettings<T>> { | ||
33 | - return this.http.get<AdminSettings<T>>(`/api/admin/settings/${key}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 32 | + public getAdminSettings<T>(key: string, config?: RequestConfig): Observable<AdminSettings<T>> { |
33 | + return this.http.get<AdminSettings<T>>(`/api/admin/settings/${key}`, defaultHttpOptionsFromConfig(config)); | ||
34 | } | 34 | } |
35 | 35 | ||
36 | public saveAdminSettings<T>(adminSettings: AdminSettings<T>, | 36 | public saveAdminSettings<T>(adminSettings: AdminSettings<T>, |
37 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<AdminSettings<T>> { | ||
38 | - return this.http.post<AdminSettings<T>>('/api/admin/settings', adminSettings, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 37 | + config?: RequestConfig): Observable<AdminSettings<T>> { |
38 | + return this.http.post<AdminSettings<T>>('/api/admin/settings', adminSettings, defaultHttpOptionsFromConfig(config)); | ||
39 | } | 39 | } |
40 | 40 | ||
41 | public sendTestMail(adminSettings: AdminSettings<MailServerSettings>, | 41 | public sendTestMail(adminSettings: AdminSettings<MailServerSettings>, |
42 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<void> { | ||
43 | - return this.http.post<void>('/api/admin/settings/testMail', adminSettings, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 42 | + config?: RequestConfig): Observable<void> { |
43 | + return this.http.post<void>('/api/admin/settings/testMail', adminSettings, defaultHttpOptionsFromConfig(config)); | ||
44 | } | 44 | } |
45 | 45 | ||
46 | - public getSecuritySettings(ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<SecuritySettings> { | ||
47 | - return this.http.get<SecuritySettings>(`/api/admin/securitySettings`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 46 | + public getSecuritySettings(config?: RequestConfig): Observable<SecuritySettings> { |
47 | + return this.http.get<SecuritySettings>(`/api/admin/securitySettings`, defaultHttpOptionsFromConfig(config)); | ||
48 | } | 48 | } |
49 | 49 | ||
50 | public saveSecuritySettings(securitySettings: SecuritySettings, | 50 | public saveSecuritySettings(securitySettings: SecuritySettings, |
51 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<SecuritySettings> { | 51 | + config?: RequestConfig): Observable<SecuritySettings> { |
52 | return this.http.post<SecuritySettings>('/api/admin/securitySettings', securitySettings, | 52 | return this.http.post<SecuritySettings>('/api/admin/securitySettings', securitySettings, |
53 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 53 | + defaultHttpOptionsFromConfig(config)); |
54 | + } | ||
55 | + | ||
56 | + public checkUpdates(config?: RequestConfig): Observable<UpdateMessage> { | ||
57 | + return this.http.get<UpdateMessage>(`/api/admin/updates`, defaultHttpOptionsFromConfig(config)); | ||
54 | } | 58 | } |
55 | } | 59 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable } from 'rxjs/index'; | 19 | import { Observable } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { PageData } from '@shared/models/page/page-data'; | 21 | import { PageData } from '@shared/models/page/page-data'; |
@@ -55,34 +55,34 @@ export class AlarmService { | @@ -55,34 +55,34 @@ export class AlarmService { | ||
55 | private http: HttpClient | 55 | private http: HttpClient |
56 | ) { } | 56 | ) { } |
57 | 57 | ||
58 | - public getAlarm(alarmId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Alarm> { | ||
59 | - return this.http.get<Alarm>(`/api/alarm/${alarmId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 58 | + public getAlarm(alarmId: string, config?: RequestConfig): Observable<Alarm> { |
59 | + return this.http.get<Alarm>(`/api/alarm/${alarmId}`, defaultHttpOptionsFromConfig(config)); | ||
60 | } | 60 | } |
61 | 61 | ||
62 | - public getAlarmInfo(alarmId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<AlarmInfo> { | ||
63 | - return this.http.get<AlarmInfo>(`/api/alarm/info/${alarmId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 62 | + public getAlarmInfo(alarmId: string, config?: RequestConfig): Observable<AlarmInfo> { |
63 | + return this.http.get<AlarmInfo>(`/api/alarm/info/${alarmId}`, defaultHttpOptionsFromConfig(config)); | ||
64 | } | 64 | } |
65 | 65 | ||
66 | - public saveAlarm(alarm: Alarm, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Alarm> { | ||
67 | - return this.http.post<Alarm>('/api/alarm', alarm, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 66 | + public saveAlarm(alarm: Alarm, config?: RequestConfig): Observable<Alarm> { |
67 | + return this.http.post<Alarm>('/api/alarm', alarm, defaultHttpOptionsFromConfig(config)); | ||
68 | } | 68 | } |
69 | 69 | ||
70 | - public ackAlarm(alarmId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<void> { | ||
71 | - return this.http.post<void>(`/api/alarm/${alarmId}/ack`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 70 | + public ackAlarm(alarmId: string, config?: RequestConfig): Observable<void> { |
71 | + return this.http.post<void>(`/api/alarm/${alarmId}/ack`, null, defaultHttpOptionsFromConfig(config)); | ||
72 | } | 72 | } |
73 | 73 | ||
74 | - public clearAlarm(alarmId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<void> { | ||
75 | - return this.http.post<void>(`/api/alarm/${alarmId}/clear`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 74 | + public clearAlarm(alarmId: string, config?: RequestConfig): Observable<void> { |
75 | + return this.http.post<void>(`/api/alarm/${alarmId}/clear`, null, defaultHttpOptionsFromConfig(config)); | ||
76 | } | 76 | } |
77 | 77 | ||
78 | public getAlarms(query: AlarmQuery, | 78 | public getAlarms(query: AlarmQuery, |
79 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<AlarmInfo>> { | 79 | + config?: RequestConfig): Observable<PageData<AlarmInfo>> { |
80 | return this.http.get<PageData<AlarmInfo>>(`/api/alarm${query.toQuery()}`, | 80 | return this.http.get<PageData<AlarmInfo>>(`/api/alarm${query.toQuery()}`, |
81 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 81 | + defaultHttpOptionsFromConfig(config)); |
82 | } | 82 | } |
83 | 83 | ||
84 | public getHighestAlarmSeverity(entityId: EntityId, alarmSearchStatus: AlarmSearchStatus, alarmStatus: AlarmStatus, | 84 | public getHighestAlarmSeverity(entityId: EntityId, alarmSearchStatus: AlarmSearchStatus, alarmStatus: AlarmStatus, |
85 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<AlarmSeverity> { | 85 | + config?: RequestConfig): Observable<AlarmSeverity> { |
86 | let url = `/api/alarm/highestSeverity/${entityId.entityType}/${entityId.entityType}`; | 86 | let url = `/api/alarm/highestSeverity/${entityId.entityType}/${entityId.entityType}`; |
87 | if (alarmSearchStatus) { | 87 | if (alarmSearchStatus) { |
88 | url += `?searchStatus=${alarmSearchStatus}`; | 88 | url += `?searchStatus=${alarmSearchStatus}`; |
@@ -90,6 +90,6 @@ export class AlarmService { | @@ -90,6 +90,6 @@ export class AlarmService { | ||
90 | url += `?status=${alarmStatus}`; | 90 | url += `?status=${alarmStatus}`; |
91 | } | 91 | } |
92 | return this.http.get<AlarmSeverity>(url, | 92 | return this.http.get<AlarmSeverity>(url, |
93 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 93 | + defaultHttpOptionsFromConfig(config)); |
94 | } | 94 | } |
95 | } | 95 | } |
@@ -14,15 +14,14 @@ | @@ -14,15 +14,14 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import {Injectable} from '@angular/core'; | ||
18 | -import {defaultHttpOptions} from './http-utils'; | ||
19 | -import {Observable} from 'rxjs/index'; | ||
20 | -import {HttpClient} from '@angular/common/http'; | ||
21 | -import {PageLink} from '@shared/models/page/page-link'; | ||
22 | -import {PageData} from '@shared/models/page/page-data'; | ||
23 | -import {EntitySubtype} from '@app/shared/models/entity-type.models'; | ||
24 | -import {Asset, AssetInfo, AssetSearchQuery} from '@app/shared/models/asset.models'; | ||
25 | -import { Device, DeviceSearchQuery } from '@shared/models/device.models'; | 17 | +import { Injectable } from '@angular/core'; |
18 | +import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; | ||
19 | +import { Observable } from 'rxjs/index'; | ||
20 | +import { HttpClient } from '@angular/common/http'; | ||
21 | +import { PageLink } from '@shared/models/page/page-link'; | ||
22 | +import { PageData } from '@shared/models/page/page-data'; | ||
23 | +import { EntitySubtype } from '@app/shared/models/entity-type.models'; | ||
24 | +import { Asset, AssetInfo, AssetSearchQuery } from '@app/shared/models/asset.models'; | ||
26 | 25 | ||
27 | @Injectable({ | 26 | @Injectable({ |
28 | providedIn: 'root' | 27 | providedIn: 'root' |
@@ -33,58 +32,61 @@ export class AssetService { | @@ -33,58 +32,61 @@ export class AssetService { | ||
33 | private http: HttpClient | 32 | private http: HttpClient |
34 | ) { } | 33 | ) { } |
35 | 34 | ||
36 | - public getTenantAssetInfos(pageLink: PageLink, type: string = '', ignoreErrors: boolean = false, | ||
37 | - ignoreLoading: boolean = false): Observable<PageData<AssetInfo>> { | 35 | + public getTenantAssetInfos(pageLink: PageLink, type: string = '', config?: RequestConfig): Observable<PageData<AssetInfo>> { |
38 | return this.http.get<PageData<AssetInfo>>(`/api/tenant/assetInfos${pageLink.toQuery()}&type=${type}`, | 36 | return this.http.get<PageData<AssetInfo>>(`/api/tenant/assetInfos${pageLink.toQuery()}&type=${type}`, |
39 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 37 | + defaultHttpOptionsFromConfig(config)); |
40 | } | 38 | } |
41 | 39 | ||
42 | - public getCustomerAssetInfos(customerId: string, pageLink: PageLink, type: string = '', ignoreErrors: boolean = false, | ||
43 | - ignoreLoading: boolean = false): Observable<PageData<AssetInfo>> { | 40 | + public getCustomerAssetInfos(customerId: string, pageLink: PageLink, type: string = '', |
41 | + config?: RequestConfig): Observable<PageData<AssetInfo>> { | ||
44 | return this.http.get<PageData<AssetInfo>>(`/api/customer/${customerId}/assetInfos${pageLink.toQuery()}&type=${type}`, | 42 | return this.http.get<PageData<AssetInfo>>(`/api/customer/${customerId}/assetInfos${pageLink.toQuery()}&type=${type}`, |
45 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 43 | + defaultHttpOptionsFromConfig(config)); |
46 | } | 44 | } |
47 | 45 | ||
48 | - public getAsset(assetId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Asset> { | ||
49 | - return this.http.get<Asset>(`/api/asset/${assetId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 46 | + public getAsset(assetId: string, config?: RequestConfig): Observable<Asset> { |
47 | + return this.http.get<Asset>(`/api/asset/${assetId}`, defaultHttpOptionsFromConfig(config)); | ||
50 | } | 48 | } |
51 | 49 | ||
52 | - public getAssets(assetIds: Array<string>, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<Asset>> { | ||
53 | - return this.http.get<Array<Asset>>(`/api/assets?assetIds=${assetIds.join(',')}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 50 | + public getAssets(assetIds: Array<string>, config?: RequestConfig): Observable<Array<Asset>> { |
51 | + return this.http.get<Array<Asset>>(`/api/assets?assetIds=${assetIds.join(',')}`, defaultHttpOptionsFromConfig(config)); | ||
54 | } | 52 | } |
55 | 53 | ||
56 | - public getAssetInfo(assetId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<AssetInfo> { | ||
57 | - return this.http.get<AssetInfo>(`/api/asset/info/${assetId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 54 | + public getAssetInfo(assetId: string, config?: RequestConfig): Observable<AssetInfo> { |
55 | + return this.http.get<AssetInfo>(`/api/asset/info/${assetId}`, defaultHttpOptionsFromConfig(config)); | ||
58 | } | 56 | } |
59 | 57 | ||
60 | - public saveAsset(asset: Asset, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Asset> { | ||
61 | - return this.http.post<Asset>('/api/asset', asset, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 58 | + public saveAsset(asset: Asset, config?: RequestConfig): Observable<Asset> { |
59 | + return this.http.post<Asset>('/api/asset', asset, defaultHttpOptionsFromConfig(config)); | ||
62 | } | 60 | } |
63 | 61 | ||
64 | - public deleteAsset(assetId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
65 | - return this.http.delete(`/api/asset/${assetId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 62 | + public deleteAsset(assetId: string, config?: RequestConfig) { |
63 | + return this.http.delete(`/api/asset/${assetId}`, defaultHttpOptionsFromConfig(config)); | ||
66 | } | 64 | } |
67 | 65 | ||
68 | - public getAssetTypes(ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntitySubtype>> { | ||
69 | - return this.http.get<Array<EntitySubtype>>('/api/asset/types', defaultHttpOptions(ignoreLoading, ignoreErrors)); | 66 | + public getAssetTypes(config?: RequestConfig): Observable<Array<EntitySubtype>> { |
67 | + return this.http.get<Array<EntitySubtype>>('/api/asset/types', defaultHttpOptionsFromConfig(config)); | ||
70 | } | 68 | } |
71 | 69 | ||
72 | - public makeAssetPublic(assetId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Asset> { | ||
73 | - return this.http.post<Asset>(`/api/customer/public/asset/${assetId}`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 70 | + public makeAssetPublic(assetId: string, config?: RequestConfig): Observable<Asset> { |
71 | + return this.http.post<Asset>(`/api/customer/public/asset/${assetId}`, null, defaultHttpOptionsFromConfig(config)); | ||
74 | } | 72 | } |
75 | 73 | ||
76 | public assignAssetToCustomer(customerId: string, assetId: string, | 74 | public assignAssetToCustomer(customerId: string, assetId: string, |
77 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Asset> { | ||
78 | - return this.http.post<Asset>(`/api/customer/${customerId}/asset/${assetId}`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 75 | + config?: RequestConfig): Observable<Asset> { |
76 | + return this.http.post<Asset>(`/api/customer/${customerId}/asset/${assetId}`, null, defaultHttpOptionsFromConfig(config)); | ||
79 | } | 77 | } |
80 | 78 | ||
81 | - public unassignAssetFromCustomer(assetId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
82 | - return this.http.delete(`/api/customer/asset/${assetId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 79 | + public unassignAssetFromCustomer(assetId: string, config?: RequestConfig) { |
80 | + return this.http.delete(`/api/customer/asset/${assetId}`, defaultHttpOptionsFromConfig(config)); | ||
83 | } | 81 | } |
84 | 82 | ||
85 | public findByQuery(query: AssetSearchQuery, | 83 | public findByQuery(query: AssetSearchQuery, |
86 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<Asset>> { | ||
87 | - return this.http.post<Array<Asset>>('/api/assets', query, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 84 | + config?: RequestConfig): Observable<Array<Asset>> { |
85 | + return this.http.post<Array<Asset>>('/api/assets', query, defaultHttpOptionsFromConfig(config)); | ||
86 | + } | ||
87 | + | ||
88 | + public findByName(assetName: string, config?: RequestConfig): Observable<Asset> { | ||
89 | + return this.http.get<Asset>(`/api/tenant/assets?assetName=${assetName}`, defaultHttpOptionsFromConfig(config)); | ||
88 | } | 90 | } |
89 | 91 | ||
90 | } | 92 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { forkJoin, Observable, of } from 'rxjs/index'; | 19 | import { forkJoin, Observable, of } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { EntityId } from '@shared/models/id/entity-id'; | 21 | import { EntityId } from '@shared/models/id/entity-id'; |
@@ -31,22 +31,30 @@ export class AttributeService { | @@ -31,22 +31,30 @@ export class AttributeService { | ||
31 | ) { } | 31 | ) { } |
32 | 32 | ||
33 | public getEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, | 33 | public getEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, |
34 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<AttributeData>> { | 34 | + config?: RequestConfig): Observable<Array<AttributeData>> { |
35 | return this.http.get<Array<AttributeData>>(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/values/attributes/` + | 35 | return this.http.get<Array<AttributeData>>(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/values/attributes/` + |
36 | `${attributeScope}`, | 36 | `${attributeScope}`, |
37 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 37 | + defaultHttpOptionsFromConfig(config)); |
38 | } | 38 | } |
39 | 39 | ||
40 | public deleteEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, attributes: Array<AttributeData>, | 40 | public deleteEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, attributes: Array<AttributeData>, |
41 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<any> { | 41 | + config?: RequestConfig): Observable<any> { |
42 | const keys = attributes.map(attribute => attribute.key).join(','); | 42 | const keys = attributes.map(attribute => attribute.key).join(','); |
43 | return this.http.delete(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/${attributeScope}` + | 43 | return this.http.delete(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/${attributeScope}` + |
44 | `?keys=${keys}`, | 44 | `?keys=${keys}`, |
45 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 45 | + defaultHttpOptionsFromConfig(config)); |
46 | + } | ||
47 | + | ||
48 | + public deleteEntityTimeseries(entityId: EntityId, timeseries: Array<AttributeData>, | ||
49 | + config?: RequestConfig): Observable<any> { | ||
50 | + const keys = timeseries.map(attribute => attribute.key).join(','); | ||
51 | + return this.http.delete(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/delete` + | ||
52 | + `?keys=${keys}`, | ||
53 | + defaultHttpOptionsFromConfig(config)); | ||
46 | } | 54 | } |
47 | 55 | ||
48 | public saveEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, attributes: Array<AttributeData>, | 56 | public saveEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, attributes: Array<AttributeData>, |
49 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<any> { | 57 | + config?: RequestConfig): Observable<any> { |
50 | const attributesData: {[key: string]: any} = {}; | 58 | const attributesData: {[key: string]: any} = {}; |
51 | const deleteAttributes: AttributeData[] = []; | 59 | const deleteAttributes: AttributeData[] = []; |
52 | attributes.forEach((attribute) => { | 60 | attributes.forEach((attribute) => { |
@@ -58,17 +66,45 @@ export class AttributeService { | @@ -58,17 +66,45 @@ export class AttributeService { | ||
58 | }); | 66 | }); |
59 | let deleteEntityAttributesObservable: Observable<any>; | 67 | let deleteEntityAttributesObservable: Observable<any>; |
60 | if (deleteAttributes.length) { | 68 | if (deleteAttributes.length) { |
61 | - deleteEntityAttributesObservable = this.deleteEntityAttributes(entityId, attributeScope, deleteAttributes); | 69 | + deleteEntityAttributesObservable = this.deleteEntityAttributes(entityId, attributeScope, deleteAttributes, config); |
62 | } else { | 70 | } else { |
63 | deleteEntityAttributesObservable = of(null); | 71 | deleteEntityAttributesObservable = of(null); |
64 | } | 72 | } |
65 | let saveEntityAttributesObservable: Observable<any>; | 73 | let saveEntityAttributesObservable: Observable<any>; |
66 | if (Object.keys(attributesData).length) { | 74 | if (Object.keys(attributesData).length) { |
67 | saveEntityAttributesObservable = this.http.post(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/${attributeScope}`, | 75 | saveEntityAttributesObservable = this.http.post(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/${attributeScope}`, |
68 | - attributesData, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 76 | + attributesData, defaultHttpOptionsFromConfig(config)); |
69 | } else { | 77 | } else { |
70 | saveEntityAttributesObservable = of(null); | 78 | saveEntityAttributesObservable = of(null); |
71 | } | 79 | } |
72 | return forkJoin(saveEntityAttributesObservable, deleteEntityAttributesObservable); | 80 | return forkJoin(saveEntityAttributesObservable, deleteEntityAttributesObservable); |
73 | } | 81 | } |
82 | + | ||
83 | + public saveEntityTimeseries(entityId: EntityId, timeseriesScope: string, timeseries: Array<AttributeData>, | ||
84 | + config?: RequestConfig): Observable<any> { | ||
85 | + const timeseriesData: {[key: string]: any} = {}; | ||
86 | + const deleteTimeseries: AttributeData[] = []; | ||
87 | + timeseries.forEach((attribute) => { | ||
88 | + if (attribute.value !== null) { | ||
89 | + timeseriesData[attribute.key] = attribute.value; | ||
90 | + } else { | ||
91 | + deleteTimeseries.push(attribute); | ||
92 | + } | ||
93 | + }); | ||
94 | + let deleteEntityTimeseriesObservable: Observable<any>; | ||
95 | + if (deleteTimeseries.length) { | ||
96 | + deleteEntityTimeseriesObservable = this.deleteEntityTimeseries(entityId, deleteTimeseries, config); | ||
97 | + } else { | ||
98 | + deleteEntityTimeseriesObservable = of(null); | ||
99 | + } | ||
100 | + let saveEntityTimeseriesObservable: Observable<any>; | ||
101 | + if (Object.keys(timeseriesData).length) { | ||
102 | + saveEntityTimeseriesObservable = | ||
103 | + this.http.post(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/${timeseriesScope}`, | ||
104 | + timeseriesData, defaultHttpOptionsFromConfig(config)); | ||
105 | + } else { | ||
106 | + saveEntityTimeseriesObservable = of(null); | ||
107 | + } | ||
108 | + return forkJoin(saveEntityTimeseriesObservable, deleteEntityTimeseriesObservable); | ||
109 | + } | ||
74 | } | 110 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable } from 'rxjs/index'; | 19 | import { Observable } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { PageLink, TimePageLink } from '@shared/models/page/page-link'; | 21 | import { PageLink, TimePageLink } from '@shared/models/page/page-link'; |
@@ -33,27 +33,27 @@ export class AuditLogService { | @@ -33,27 +33,27 @@ export class AuditLogService { | ||
33 | ) { } | 33 | ) { } |
34 | 34 | ||
35 | public getAuditLogs(pageLink: TimePageLink, | 35 | public getAuditLogs(pageLink: TimePageLink, |
36 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<AuditLog>> { | 36 | + config?: RequestConfig): Observable<PageData<AuditLog>> { |
37 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs${pageLink.toQuery()}`, | 37 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs${pageLink.toQuery()}`, |
38 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 38 | + defaultHttpOptionsFromConfig(config)); |
39 | } | 39 | } |
40 | 40 | ||
41 | public getAuditLogsByCustomerId(customerId: string, pageLink: TimePageLink, | 41 | public getAuditLogsByCustomerId(customerId: string, pageLink: TimePageLink, |
42 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<AuditLog>> { | 42 | + config?: RequestConfig): Observable<PageData<AuditLog>> { |
43 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs/customer/${customerId}${pageLink.toQuery()}`, | 43 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs/customer/${customerId}${pageLink.toQuery()}`, |
44 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 44 | + defaultHttpOptionsFromConfig(config)); |
45 | } | 45 | } |
46 | 46 | ||
47 | public getAuditLogsByUserId(userId: string, pageLink: TimePageLink, | 47 | public getAuditLogsByUserId(userId: string, pageLink: TimePageLink, |
48 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<AuditLog>> { | 48 | + config?: RequestConfig): Observable<PageData<AuditLog>> { |
49 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs/user/${userId}${pageLink.toQuery()}`, | 49 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs/user/${userId}${pageLink.toQuery()}`, |
50 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 50 | + defaultHttpOptionsFromConfig(config)); |
51 | } | 51 | } |
52 | 52 | ||
53 | public getAuditLogsByEntityId(entityId: EntityId, pageLink: TimePageLink, | 53 | public getAuditLogsByEntityId(entityId: EntityId, pageLink: TimePageLink, |
54 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<AuditLog>> { | 54 | + config?: RequestConfig): Observable<PageData<AuditLog>> { |
55 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs/entity/${entityId.entityType}/${entityId.id}${pageLink.toQuery()}`, | 55 | return this.http.get<PageData<AuditLog>>(`/api/audit/logs/entity/${entityId.entityType}/${entityId.id}${pageLink.toQuery()}`, |
56 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 56 | + defaultHttpOptionsFromConfig(config)); |
57 | } | 57 | } |
58 | 58 | ||
59 | } | 59 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable } from 'rxjs/index'; | 19 | import { Observable } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { PageLink } from '@shared/models/page/page-link'; | 21 | import { PageLink } from '@shared/models/page/page-link'; |
@@ -31,22 +31,21 @@ export class CustomerService { | @@ -31,22 +31,21 @@ export class CustomerService { | ||
31 | private http: HttpClient | 31 | private http: HttpClient |
32 | ) { } | 32 | ) { } |
33 | 33 | ||
34 | - public getCustomers(pageLink: PageLink, ignoreErrors: boolean = false, | ||
35 | - ignoreLoading: boolean = false): Observable<PageData<Customer>> { | 34 | + public getCustomers(pageLink: PageLink, config?: RequestConfig): Observable<PageData<Customer>> { |
36 | return this.http.get<PageData<Customer>>(`/api/customers${pageLink.toQuery()}`, | 35 | return this.http.get<PageData<Customer>>(`/api/customers${pageLink.toQuery()}`, |
37 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 36 | + defaultHttpOptionsFromConfig(config)); |
38 | } | 37 | } |
39 | 38 | ||
40 | - public getCustomer(customerId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Customer> { | ||
41 | - return this.http.get<Customer>(`/api/customer/${customerId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 39 | + public getCustomer(customerId: string, config?: RequestConfig): Observable<Customer> { |
40 | + return this.http.get<Customer>(`/api/customer/${customerId}`, defaultHttpOptionsFromConfig(config)); | ||
42 | } | 41 | } |
43 | 42 | ||
44 | - public saveCustomer(customer: Customer, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Customer> { | ||
45 | - return this.http.post<Customer>('/api/customer', customer, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 43 | + public saveCustomer(customer: Customer, config?: RequestConfig): Observable<Customer> { |
44 | + return this.http.post<Customer>('/api/customer', customer, defaultHttpOptionsFromConfig(config)); | ||
46 | } | 45 | } |
47 | 46 | ||
48 | - public deleteCustomer(customerId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
49 | - return this.http.delete(`/api/customer/${customerId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 47 | + public deleteCustomer(customerId: string, config?: RequestConfig) { |
48 | + return this.http.delete(`/api/customer/${customerId}`, defaultHttpOptionsFromConfig(config)); | ||
50 | } | 49 | } |
51 | 50 | ||
52 | } | 51 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import {Inject, Injectable} from '@angular/core'; | 17 | import {Inject, Injectable} from '@angular/core'; |
18 | -import {defaultHttpOptions} from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable, ReplaySubject, Subject } from 'rxjs/index'; | 19 | import { Observable, ReplaySubject, Subject } from 'rxjs/index'; |
20 | import {HttpClient} from '@angular/common/http'; | 20 | import {HttpClient} from '@angular/common/http'; |
21 | import {PageLink} from '@shared/models/page/page-link'; | 21 | import {PageLink} from '@shared/models/page/page-link'; |
@@ -50,77 +50,75 @@ export class DashboardService { | @@ -50,77 +50,75 @@ export class DashboardService { | ||
50 | ); | 50 | ); |
51 | } | 51 | } |
52 | 52 | ||
53 | - public getTenantDashboards(pageLink: PageLink, ignoreErrors: boolean = false, | ||
54 | - ignoreLoading: boolean = false): Observable<PageData<DashboardInfo>> { | 53 | + public getTenantDashboards(pageLink: PageLink, config?: RequestConfig): Observable<PageData<DashboardInfo>> { |
55 | return this.http.get<PageData<DashboardInfo>>(`/api/tenant/dashboards${pageLink.toQuery()}`, | 54 | return this.http.get<PageData<DashboardInfo>>(`/api/tenant/dashboards${pageLink.toQuery()}`, |
56 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 55 | + defaultHttpOptionsFromConfig(config)); |
57 | } | 56 | } |
58 | 57 | ||
59 | - public getTenantDashboardsByTenantId(tenantId: string, pageLink: PageLink, ignoreErrors: boolean = false, | ||
60 | - ignoreLoading: boolean = false): Observable<PageData<DashboardInfo>> { | 58 | + public getTenantDashboardsByTenantId(tenantId: string, pageLink: PageLink, |
59 | + config?: RequestConfig): Observable<PageData<DashboardInfo>> { | ||
61 | return this.http.get<PageData<DashboardInfo>>(`/api/tenant/${tenantId}/dashboards${pageLink.toQuery()}`, | 60 | return this.http.get<PageData<DashboardInfo>>(`/api/tenant/${tenantId}/dashboards${pageLink.toQuery()}`, |
62 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 61 | + defaultHttpOptionsFromConfig(config)); |
63 | } | 62 | } |
64 | 63 | ||
65 | - public getCustomerDashboards(customerId: string, pageLink: PageLink, ignoreErrors: boolean = false, | ||
66 | - ignoreLoading: boolean = false): Observable<PageData<DashboardInfo>> { | 64 | + public getCustomerDashboards(customerId: string, pageLink: PageLink, config?: RequestConfig): Observable<PageData<DashboardInfo>> { |
67 | return this.http.get<PageData<DashboardInfo>>(`/api/customer/${customerId}/dashboards${pageLink.toQuery()}`, | 65 | return this.http.get<PageData<DashboardInfo>>(`/api/customer/${customerId}/dashboards${pageLink.toQuery()}`, |
68 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 66 | + defaultHttpOptionsFromConfig(config)); |
69 | } | 67 | } |
70 | 68 | ||
71 | - public getDashboard(dashboardId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | ||
72 | - return this.http.get<Dashboard>(`/api/dashboard/${dashboardId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 69 | + public getDashboard(dashboardId: string, config?: RequestConfig): Observable<Dashboard> { |
70 | + return this.http.get<Dashboard>(`/api/dashboard/${dashboardId}`, defaultHttpOptionsFromConfig(config)); | ||
73 | } | 71 | } |
74 | 72 | ||
75 | - public getDashboardInfo(dashboardId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<DashboardInfo> { | ||
76 | - return this.http.get<DashboardInfo>(`/api/dashboard/info/${dashboardId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 73 | + public getDashboardInfo(dashboardId: string, config?: RequestConfig): Observable<DashboardInfo> { |
74 | + return this.http.get<DashboardInfo>(`/api/dashboard/info/${dashboardId}`, defaultHttpOptionsFromConfig(config)); | ||
77 | } | 75 | } |
78 | 76 | ||
79 | - public saveDashboard(dashboard: Dashboard, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | ||
80 | - return this.http.post<Dashboard>('/api/dashboard', dashboard, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 77 | + public saveDashboard(dashboard: Dashboard, config?: RequestConfig): Observable<Dashboard> { |
78 | + return this.http.post<Dashboard>('/api/dashboard', dashboard, defaultHttpOptionsFromConfig(config)); | ||
81 | } | 79 | } |
82 | 80 | ||
83 | - public deleteDashboard(dashboardId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
84 | - return this.http.delete(`/api/dashboard/${dashboardId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 81 | + public deleteDashboard(dashboardId: string, config?: RequestConfig) { |
82 | + return this.http.delete(`/api/dashboard/${dashboardId}`, defaultHttpOptionsFromConfig(config)); | ||
85 | } | 83 | } |
86 | 84 | ||
87 | public assignDashboardToCustomer(customerId: string, dashboardId: string, | 85 | public assignDashboardToCustomer(customerId: string, dashboardId: string, |
88 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | 86 | + config?: RequestConfig): Observable<Dashboard> { |
89 | return this.http.post<Dashboard>(`/api/customer/${customerId}/dashboard/${dashboardId}`, | 87 | return this.http.post<Dashboard>(`/api/customer/${customerId}/dashboard/${dashboardId}`, |
90 | - null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 88 | + null, defaultHttpOptionsFromConfig(config)); |
91 | } | 89 | } |
92 | 90 | ||
93 | public unassignDashboardFromCustomer(customerId: string, dashboardId: string, | 91 | public unassignDashboardFromCustomer(customerId: string, dashboardId: string, |
94 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
95 | - return this.http.delete(`/api/customer/${customerId}/dashboard/${dashboardId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 92 | + config?: RequestConfig) { |
93 | + return this.http.delete(`/api/customer/${customerId}/dashboard/${dashboardId}`, defaultHttpOptionsFromConfig(config)); | ||
96 | } | 94 | } |
97 | 95 | ||
98 | - public makeDashboardPublic(dashboardId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | 96 | + public makeDashboardPublic(dashboardId: string, config?: RequestConfig): Observable<Dashboard> { |
99 | return this.http.post<Dashboard>(`/api/customer/public/dashboard/${dashboardId}`, null, | 97 | return this.http.post<Dashboard>(`/api/customer/public/dashboard/${dashboardId}`, null, |
100 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 98 | + defaultHttpOptionsFromConfig(config)); |
101 | } | 99 | } |
102 | 100 | ||
103 | - public makeDashboardPrivate(dashboardId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | 101 | + public makeDashboardPrivate(dashboardId: string, config?: RequestConfig): Observable<Dashboard> { |
104 | return this.http.delete<Dashboard>(`/api/customer/public/dashboard/${dashboardId}`, | 102 | return this.http.delete<Dashboard>(`/api/customer/public/dashboard/${dashboardId}`, |
105 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 103 | + defaultHttpOptionsFromConfig(config)); |
106 | } | 104 | } |
107 | 105 | ||
108 | public updateDashboardCustomers(dashboardId: string, customerIds: Array<string>, | 106 | public updateDashboardCustomers(dashboardId: string, customerIds: Array<string>, |
109 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | 107 | + config?: RequestConfig): Observable<Dashboard> { |
110 | return this.http.post<Dashboard>(`/api/dashboard/${dashboardId}/customers`, customerIds, | 108 | return this.http.post<Dashboard>(`/api/dashboard/${dashboardId}/customers`, customerIds, |
111 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 109 | + defaultHttpOptionsFromConfig(config)); |
112 | } | 110 | } |
113 | 111 | ||
114 | public addDashboardCustomers(dashboardId: string, customerIds: Array<string>, | 112 | public addDashboardCustomers(dashboardId: string, customerIds: Array<string>, |
115 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | 113 | + config?: RequestConfig): Observable<Dashboard> { |
116 | return this.http.post<Dashboard>(`/api/dashboard/${dashboardId}/customers/add`, customerIds, | 114 | return this.http.post<Dashboard>(`/api/dashboard/${dashboardId}/customers/add`, customerIds, |
117 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 115 | + defaultHttpOptionsFromConfig(config)); |
118 | } | 116 | } |
119 | 117 | ||
120 | public removeDashboardCustomers(dashboardId: string, customerIds: Array<string>, | 118 | public removeDashboardCustomers(dashboardId: string, customerIds: Array<string>, |
121 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Dashboard> { | 119 | + config?: RequestConfig): Observable<Dashboard> { |
122 | return this.http.post<Dashboard>(`/api/dashboard/${dashboardId}/customers/remove`, customerIds, | 120 | return this.http.post<Dashboard>(`/api/dashboard/${dashboardId}/customers/remove`, customerIds, |
123 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 121 | + defaultHttpOptionsFromConfig(config)); |
124 | } | 122 | } |
125 | 123 | ||
126 | public getPublicDashboardLink(dashboard: DashboardInfo): string | null { | 124 | public getPublicDashboardLink(dashboard: DashboardInfo): string | null { |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable, Subject, ReplaySubject } from 'rxjs/index'; | 19 | import { Observable, Subject, ReplaySubject } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { PageLink } from '@shared/models/page/page-link'; | 21 | import { PageLink } from '@shared/models/page/page-link'; |
@@ -36,44 +36,43 @@ export class DeviceService { | @@ -36,44 +36,43 @@ export class DeviceService { | ||
36 | private http: HttpClient | 36 | private http: HttpClient |
37 | ) { } | 37 | ) { } |
38 | 38 | ||
39 | - public getTenantDeviceInfos(pageLink: PageLink, type: string = '', ignoreErrors: boolean = false, | ||
40 | - ignoreLoading: boolean = false): Observable<PageData<DeviceInfo>> { | 39 | + public getTenantDeviceInfos(pageLink: PageLink, type: string = '', |
40 | + config?: RequestConfig): Observable<PageData<DeviceInfo>> { | ||
41 | return this.http.get<PageData<DeviceInfo>>(`/api/tenant/deviceInfos${pageLink.toQuery()}&type=${type}`, | 41 | return this.http.get<PageData<DeviceInfo>>(`/api/tenant/deviceInfos${pageLink.toQuery()}&type=${type}`, |
42 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 42 | + defaultHttpOptionsFromConfig(config)); |
43 | } | 43 | } |
44 | 44 | ||
45 | - public getCustomerDeviceInfos(customerId: string, pageLink: PageLink, type: string = '', ignoreErrors: boolean = false, | ||
46 | - ignoreLoading: boolean = false): Observable<PageData<DeviceInfo>> { | 45 | + public getCustomerDeviceInfos(customerId: string, pageLink: PageLink, type: string = '', |
46 | + config?: RequestConfig): Observable<PageData<DeviceInfo>> { | ||
47 | return this.http.get<PageData<DeviceInfo>>(`/api/customer/${customerId}/deviceInfos${pageLink.toQuery()}&type=${type}`, | 47 | return this.http.get<PageData<DeviceInfo>>(`/api/customer/${customerId}/deviceInfos${pageLink.toQuery()}&type=${type}`, |
48 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 48 | + defaultHttpOptionsFromConfig(config)); |
49 | } | 49 | } |
50 | 50 | ||
51 | - public getDevice(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Device> { | ||
52 | - return this.http.get<Device>(`/api/device/${deviceId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 51 | + public getDevice(deviceId: string, config?: RequestConfig): Observable<Device> { |
52 | + return this.http.get<Device>(`/api/device/${deviceId}`, defaultHttpOptionsFromConfig(config)); | ||
53 | } | 53 | } |
54 | 54 | ||
55 | - public getDevices(deviceIds: Array<string>, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<Device>> { | ||
56 | - return this.http.get<Array<Device>>(`/api/devices?deviceIds=${deviceIds.join(',')}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 55 | + public getDevices(deviceIds: Array<string>, config?: RequestConfig): Observable<Array<Device>> { |
56 | + return this.http.get<Array<Device>>(`/api/devices?deviceIds=${deviceIds.join(',')}`, defaultHttpOptionsFromConfig(config)); | ||
57 | } | 57 | } |
58 | 58 | ||
59 | - public getDeviceInfo(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<DeviceInfo> { | ||
60 | - return this.http.get<DeviceInfo>(`/api/device/info/${deviceId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 59 | + public getDeviceInfo(deviceId: string, config?: RequestConfig): Observable<DeviceInfo> { |
60 | + return this.http.get<DeviceInfo>(`/api/device/info/${deviceId}`, defaultHttpOptionsFromConfig(config)); | ||
61 | } | 61 | } |
62 | 62 | ||
63 | - public saveDevice(device: Device, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Device> { | ||
64 | - return this.http.post<Device>('/api/device', device, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 63 | + public saveDevice(device: Device, config?: RequestConfig): Observable<Device> { |
64 | + return this.http.post<Device>('/api/device', device, defaultHttpOptionsFromConfig(config)); | ||
65 | } | 65 | } |
66 | 66 | ||
67 | - public deleteDevice(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
68 | - return this.http.delete(`/api/device/${deviceId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 67 | + public deleteDevice(deviceId: string, config?: RequestConfig) { |
68 | + return this.http.delete(`/api/device/${deviceId}`, defaultHttpOptionsFromConfig(config)); | ||
69 | } | 69 | } |
70 | 70 | ||
71 | - public getDeviceTypes(ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntitySubtype>> { | ||
72 | - return this.http.get<Array<EntitySubtype>>('/api/device/types', defaultHttpOptions(ignoreLoading, ignoreErrors)); | 71 | + public getDeviceTypes(config?: RequestConfig): Observable<Array<EntitySubtype>> { |
72 | + return this.http.get<Array<EntitySubtype>>('/api/device/types', defaultHttpOptionsFromConfig(config)); | ||
73 | } | 73 | } |
74 | 74 | ||
75 | - public getDeviceCredentials(deviceId: string, sync: boolean = false, ignoreErrors: boolean = false, | ||
76 | - ignoreLoading: boolean = false): Observable<DeviceCredentials> { | 75 | + public getDeviceCredentials(deviceId: string, sync: boolean = false, config?: RequestConfig): Observable<DeviceCredentials> { |
77 | const url = `/api/device/${deviceId}/credentials`; | 76 | const url = `/api/device/${deviceId}/credentials`; |
78 | if (sync) { | 77 | if (sync) { |
79 | const responseSubject = new ReplaySubject<DeviceCredentials>(); | 78 | const responseSubject = new ReplaySubject<DeviceCredentials>(); |
@@ -93,31 +92,34 @@ export class DeviceService { | @@ -93,31 +92,34 @@ export class DeviceService { | ||
93 | } | 92 | } |
94 | return responseSubject.asObservable(); | 93 | return responseSubject.asObservable(); |
95 | } else { | 94 | } else { |
96 | - return this.http.get<DeviceCredentials>(url, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 95 | + return this.http.get<DeviceCredentials>(url, defaultHttpOptionsFromConfig(config)); |
97 | } | 96 | } |
98 | } | 97 | } |
99 | 98 | ||
100 | - public saveDeviceCredentials(deviceCredentials: DeviceCredentials, ignoreErrors: boolean = false, | ||
101 | - ignoreLoading: boolean = false): Observable<DeviceCredentials> { | ||
102 | - return this.http.post<DeviceCredentials>('/api/device/credentials', deviceCredentials, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 99 | + public saveDeviceCredentials(deviceCredentials: DeviceCredentials, config?: RequestConfig): Observable<DeviceCredentials> { |
100 | + return this.http.post<DeviceCredentials>('/api/device/credentials', deviceCredentials, defaultHttpOptionsFromConfig(config)); | ||
103 | } | 101 | } |
104 | 102 | ||
105 | - public makeDevicePublic(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Device> { | ||
106 | - return this.http.post<Device>(`/api/customer/public/device/${deviceId}`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 103 | + public makeDevicePublic(deviceId: string, config?: RequestConfig): Observable<Device> { |
104 | + return this.http.post<Device>(`/api/customer/public/device/${deviceId}`, null, defaultHttpOptionsFromConfig(config)); | ||
107 | } | 105 | } |
108 | 106 | ||
109 | public assignDeviceToCustomer(customerId: string, deviceId: string, | 107 | public assignDeviceToCustomer(customerId: string, deviceId: string, |
110 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Device> { | ||
111 | - return this.http.post<Device>(`/api/customer/${customerId}/device/${deviceId}`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 108 | + config?: RequestConfig): Observable<Device> { |
109 | + return this.http.post<Device>(`/api/customer/${customerId}/device/${deviceId}`, null, defaultHttpOptionsFromConfig(config)); | ||
112 | } | 110 | } |
113 | 111 | ||
114 | - public unassignDeviceFromCustomer(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
115 | - return this.http.delete(`/api/customer/device/${deviceId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 112 | + public unassignDeviceFromCustomer(deviceId: string, config?: RequestConfig) { |
113 | + return this.http.delete(`/api/customer/device/${deviceId}`, defaultHttpOptionsFromConfig(config)); | ||
116 | } | 114 | } |
117 | 115 | ||
118 | public findByQuery(query: DeviceSearchQuery, | 116 | public findByQuery(query: DeviceSearchQuery, |
119 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<Device>> { | ||
120 | - return this.http.post<Array<Device>>('/api/devices', query, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 117 | + config?: RequestConfig): Observable<Array<Device>> { |
118 | + return this.http.post<Array<Device>>('/api/devices', query, defaultHttpOptionsFromConfig(config)); | ||
119 | + } | ||
120 | + | ||
121 | + public findByName(deviceName: string, config?: RequestConfig): Observable<Device> { | ||
122 | + return this.http.get<Device>(`/api/tenant/devices?deviceName=${deviceName}`, defaultHttpOptionsFromConfig(config)); | ||
121 | } | 123 | } |
122 | 124 | ||
123 | } | 125 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable } from 'rxjs/index'; | 19 | import { Observable } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { EntityRelation, EntityRelationInfo, EntityRelationsQuery } from '@shared/models/relation.models'; | 21 | import { EntityRelation, EntityRelationInfo, EntityRelationsQuery } from '@shared/models/relation.models'; |
@@ -30,84 +30,84 @@ export class EntityRelationService { | @@ -30,84 +30,84 @@ export class EntityRelationService { | ||
30 | private http: HttpClient | 30 | private http: HttpClient |
31 | ) { } | 31 | ) { } |
32 | 32 | ||
33 | - public saveRelation(relation: EntityRelation, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<EntityRelation> { | ||
34 | - return this.http.post<EntityRelation>('/api/relation', relation, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 33 | + public saveRelation(relation: EntityRelation, config?: RequestConfig): Observable<EntityRelation> { |
34 | + return this.http.post<EntityRelation>('/api/relation', relation, defaultHttpOptionsFromConfig(config)); | ||
35 | } | 35 | } |
36 | 36 | ||
37 | public deleteRelation(fromId: EntityId, relationType: string, toId: EntityId, | 37 | public deleteRelation(fromId: EntityId, relationType: string, toId: EntityId, |
38 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | 38 | + config?: RequestConfig) { |
39 | return this.http.delete(`/api/relation?fromId=${fromId.id}&fromType=${fromId.entityType}` + | 39 | return this.http.delete(`/api/relation?fromId=${fromId.id}&fromType=${fromId.entityType}` + |
40 | `&relationType=${relationType}&toId=${toId.id}&toType=${toId.entityType}`, | 40 | `&relationType=${relationType}&toId=${toId.id}&toType=${toId.entityType}`, |
41 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 41 | + defaultHttpOptionsFromConfig(config)); |
42 | } | 42 | } |
43 | 43 | ||
44 | public deleteRelations(entityId: EntityId, | 44 | public deleteRelations(entityId: EntityId, |
45 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | 45 | + config?: RequestConfig) { |
46 | return this.http.delete(`/api/relations?entityId=${entityId.id}&entityType=${entityId.entityType}`, | 46 | return this.http.delete(`/api/relations?entityId=${entityId.id}&entityType=${entityId.entityType}`, |
47 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 47 | + defaultHttpOptionsFromConfig(config)); |
48 | } | 48 | } |
49 | 49 | ||
50 | public getRelation(fromId: EntityId, relationType: string, toId: EntityId, | 50 | public getRelation(fromId: EntityId, relationType: string, toId: EntityId, |
51 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<EntityRelation> { | 51 | + config?: RequestConfig): Observable<EntityRelation> { |
52 | return this.http.get<EntityRelation>(`/api/relation?fromId=${fromId.id}&fromType=${fromId.entityType}` + | 52 | return this.http.get<EntityRelation>(`/api/relation?fromId=${fromId.id}&fromType=${fromId.entityType}` + |
53 | `&relationType=${relationType}&toId=${toId.id}&toType=${toId.entityType}`, | 53 | `&relationType=${relationType}&toId=${toId.id}&toType=${toId.entityType}`, |
54 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 54 | + defaultHttpOptionsFromConfig(config)); |
55 | } | 55 | } |
56 | 56 | ||
57 | public findByFrom(fromId: EntityId, | 57 | public findByFrom(fromId: EntityId, |
58 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelation>> { | 58 | + config?: RequestConfig): Observable<Array<EntityRelation>> { |
59 | return this.http.get<Array<EntityRelation>>( | 59 | return this.http.get<Array<EntityRelation>>( |
60 | `/api/relations?fromId=${fromId.id}&fromType=${fromId.entityType}`, | 60 | `/api/relations?fromId=${fromId.id}&fromType=${fromId.entityType}`, |
61 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 61 | + defaultHttpOptionsFromConfig(config)); |
62 | } | 62 | } |
63 | 63 | ||
64 | public findInfoByFrom(fromId: EntityId, | 64 | public findInfoByFrom(fromId: EntityId, |
65 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelationInfo>> { | 65 | + config?: RequestConfig): Observable<Array<EntityRelationInfo>> { |
66 | return this.http.get<Array<EntityRelationInfo>>( | 66 | return this.http.get<Array<EntityRelationInfo>>( |
67 | `/api/relations/info?fromId=${fromId.id}&fromType=${fromId.entityType}`, | 67 | `/api/relations/info?fromId=${fromId.id}&fromType=${fromId.entityType}`, |
68 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 68 | + defaultHttpOptionsFromConfig(config)); |
69 | } | 69 | } |
70 | 70 | ||
71 | public findByFromAndType(fromId: EntityId, relationType: string, | 71 | public findByFromAndType(fromId: EntityId, relationType: string, |
72 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelation>> { | 72 | + config?: RequestConfig): Observable<Array<EntityRelation>> { |
73 | return this.http.get<Array<EntityRelation>>( | 73 | return this.http.get<Array<EntityRelation>>( |
74 | `/api/relations?fromId=${fromId.id}&fromType=${fromId.entityType}&relationType=${relationType}`, | 74 | `/api/relations?fromId=${fromId.id}&fromType=${fromId.entityType}&relationType=${relationType}`, |
75 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 75 | + defaultHttpOptionsFromConfig(config)); |
76 | } | 76 | } |
77 | 77 | ||
78 | public findByTo(toId: EntityId, | 78 | public findByTo(toId: EntityId, |
79 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelation>> { | 79 | + config?: RequestConfig): Observable<Array<EntityRelation>> { |
80 | return this.http.get<Array<EntityRelation>>( | 80 | return this.http.get<Array<EntityRelation>>( |
81 | `/api/relations?toId=${toId.id}&toType=${toId.entityType}`, | 81 | `/api/relations?toId=${toId.id}&toType=${toId.entityType}`, |
82 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 82 | + defaultHttpOptionsFromConfig(config)); |
83 | } | 83 | } |
84 | 84 | ||
85 | public findInfoByTo(toId: EntityId, | 85 | public findInfoByTo(toId: EntityId, |
86 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelationInfo>> { | 86 | + config?: RequestConfig): Observable<Array<EntityRelationInfo>> { |
87 | return this.http.get<Array<EntityRelationInfo>>( | 87 | return this.http.get<Array<EntityRelationInfo>>( |
88 | `/api/relations/info?toId=${toId.id}&toType=${toId.entityType}`, | 88 | `/api/relations/info?toId=${toId.id}&toType=${toId.entityType}`, |
89 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 89 | + defaultHttpOptionsFromConfig(config)); |
90 | } | 90 | } |
91 | 91 | ||
92 | public findByToAndType(toId: EntityId, relationType: string, | 92 | public findByToAndType(toId: EntityId, relationType: string, |
93 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelation>> { | 93 | + config?: RequestConfig): Observable<Array<EntityRelation>> { |
94 | return this.http.get<Array<EntityRelation>>( | 94 | return this.http.get<Array<EntityRelation>>( |
95 | `/api/relations?toId=${toId.id}&toType=${toId.entityType}&relationType=${relationType}`, | 95 | `/api/relations?toId=${toId.id}&toType=${toId.entityType}&relationType=${relationType}`, |
96 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 96 | + defaultHttpOptionsFromConfig(config)); |
97 | } | 97 | } |
98 | 98 | ||
99 | public findByQuery(query: EntityRelationsQuery, | 99 | public findByQuery(query: EntityRelationsQuery, |
100 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelation>> { | 100 | + config?: RequestConfig): Observable<Array<EntityRelation>> { |
101 | return this.http.post<Array<EntityRelation>>( | 101 | return this.http.post<Array<EntityRelation>>( |
102 | '/api/relations', query, | 102 | '/api/relations', query, |
103 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 103 | + defaultHttpOptionsFromConfig(config)); |
104 | } | 104 | } |
105 | 105 | ||
106 | public findInfoByQuery(query: EntityRelationsQuery, | 106 | public findInfoByQuery(query: EntityRelationsQuery, |
107 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityRelationInfo>> { | 107 | + config?: RequestConfig): Observable<Array<EntityRelationInfo>> { |
108 | return this.http.post<Array<EntityRelationInfo>>( | 108 | return this.http.post<Array<EntityRelationInfo>>( |
109 | '/api/relations/info', query, | 109 | '/api/relations/info', query, |
110 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 110 | + defaultHttpOptionsFromConfig(config)); |
111 | } | 111 | } |
112 | 112 | ||
113 | } | 113 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import {Injectable} from '@angular/core'; | 17 | import {Injectable} from '@angular/core'; |
18 | -import {defaultHttpOptions} from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import {Observable} from 'rxjs/index'; | 19 | import {Observable} from 'rxjs/index'; |
20 | import {HttpClient} from '@angular/common/http'; | 20 | import {HttpClient} from '@angular/common/http'; |
21 | import {PageLink} from '@shared/models/page/page-link'; | 21 | import {PageLink} from '@shared/models/page/page-link'; |
@@ -33,57 +33,55 @@ export class EntityViewService { | @@ -33,57 +33,55 @@ export class EntityViewService { | ||
33 | private http: HttpClient | 33 | private http: HttpClient |
34 | ) { } | 34 | ) { } |
35 | 35 | ||
36 | - public getTenantEntityViewInfos(pageLink: PageLink, type: string = '', ignoreErrors: boolean = false, | ||
37 | - ignoreLoading: boolean = false): Observable<PageData<EntityViewInfo>> { | 36 | + public getTenantEntityViewInfos(pageLink: PageLink, type: string = '', config?: RequestConfig): Observable<PageData<EntityViewInfo>> { |
38 | return this.http.get<PageData<EntityViewInfo>>(`/api/tenant/entityViewInfos${pageLink.toQuery()}&type=${type}`, | 37 | return this.http.get<PageData<EntityViewInfo>>(`/api/tenant/entityViewInfos${pageLink.toQuery()}&type=${type}`, |
39 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 38 | + defaultHttpOptionsFromConfig(config)); |
40 | } | 39 | } |
41 | 40 | ||
42 | - public getCustomerEntityViewInfos(customerId: string, pageLink: PageLink, type: string = '', ignoreErrors: boolean = false, | ||
43 | - ignoreLoading: boolean = false): Observable<PageData<EntityViewInfo>> { | 41 | + public getCustomerEntityViewInfos(customerId: string, pageLink: PageLink, type: string = '', |
42 | + config?: RequestConfig): Observable<PageData<EntityViewInfo>> { | ||
44 | return this.http.get<PageData<EntityViewInfo>>(`/api/customer/${customerId}/entityViewInfos${pageLink.toQuery()}&type=${type}`, | 43 | return this.http.get<PageData<EntityViewInfo>>(`/api/customer/${customerId}/entityViewInfos${pageLink.toQuery()}&type=${type}`, |
45 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 44 | + defaultHttpOptionsFromConfig(config)); |
46 | } | 45 | } |
47 | 46 | ||
48 | - public getEntityView(entityViewId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<EntityView> { | ||
49 | - return this.http.get<EntityView>(`/api/entityView/${entityViewId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 47 | + public getEntityView(entityViewId: string, config?: RequestConfig): Observable<EntityView> { |
48 | + return this.http.get<EntityView>(`/api/entityView/${entityViewId}`, defaultHttpOptionsFromConfig(config)); | ||
50 | } | 49 | } |
51 | 50 | ||
52 | - public getEntityViewInfo(entityViewId: string, ignoreErrors: boolean = false, | ||
53 | - ignoreLoading: boolean = false): Observable<EntityViewInfo> { | ||
54 | - return this.http.get<EntityViewInfo>(`/api/entityView/info/${entityViewId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 51 | + public getEntityViewInfo(entityViewId: string, config?: RequestConfig): Observable<EntityViewInfo> { |
52 | + return this.http.get<EntityViewInfo>(`/api/entityView/info/${entityViewId}`, defaultHttpOptionsFromConfig(config)); | ||
55 | } | 53 | } |
56 | 54 | ||
57 | - public saveEntityView(entityView: EntityView, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<EntityView> { | ||
58 | - return this.http.post<EntityView>('/api/entityView', entityView, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 55 | + public saveEntityView(entityView: EntityView, config?: RequestConfig): Observable<EntityView> { |
56 | + return this.http.post<EntityView>('/api/entityView', entityView, defaultHttpOptionsFromConfig(config)); | ||
59 | } | 57 | } |
60 | 58 | ||
61 | - public deleteEntityView(entityViewId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
62 | - return this.http.delete(`/api/entityView/${entityViewId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 59 | + public deleteEntityView(entityViewId: string, config?: RequestConfig) { |
60 | + return this.http.delete(`/api/entityView/${entityViewId}`, defaultHttpOptionsFromConfig(config)); | ||
63 | } | 61 | } |
64 | 62 | ||
65 | - public getEntityViewTypes(ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntitySubtype>> { | ||
66 | - return this.http.get<Array<EntitySubtype>>('/api/entityView/types', defaultHttpOptions(ignoreLoading, ignoreErrors)); | 63 | + public getEntityViewTypes(config?: RequestConfig): Observable<Array<EntitySubtype>> { |
64 | + return this.http.get<Array<EntitySubtype>>('/api/entityView/types', defaultHttpOptionsFromConfig(config)); | ||
67 | } | 65 | } |
68 | 66 | ||
69 | - public makeEntityViewPublic(entityViewId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<EntityView> { | 67 | + public makeEntityViewPublic(entityViewId: string, config?: RequestConfig): Observable<EntityView> { |
70 | return this.http.post<EntityView>(`/api/customer/public/entityView/${entityViewId}`, null, | 68 | return this.http.post<EntityView>(`/api/customer/public/entityView/${entityViewId}`, null, |
71 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 69 | + defaultHttpOptionsFromConfig(config)); |
72 | } | 70 | } |
73 | 71 | ||
74 | public assignEntityViewToCustomer(customerId: string, entityViewId: string, | 72 | public assignEntityViewToCustomer(customerId: string, entityViewId: string, |
75 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<EntityView> { | 73 | + config?: RequestConfig): Observable<EntityView> { |
76 | return this.http.post<EntityView>(`/api/customer/${customerId}/entityView/${entityViewId}`, null, | 74 | return this.http.post<EntityView>(`/api/customer/${customerId}/entityView/${entityViewId}`, null, |
77 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 75 | + defaultHttpOptionsFromConfig(config)); |
78 | } | 76 | } |
79 | 77 | ||
80 | - public unassignEntityViewFromCustomer(entityViewId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
81 | - return this.http.delete(`/api/customer/entityView/${entityViewId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 78 | + public unassignEntityViewFromCustomer(entityViewId: string, config?: RequestConfig) { |
79 | + return this.http.delete(`/api/customer/entityView/${entityViewId}`, defaultHttpOptionsFromConfig(config)); | ||
82 | } | 80 | } |
83 | 81 | ||
84 | public findByQuery(query: EntityViewSearchQuery, | 82 | public findByQuery(query: EntityViewSearchQuery, |
85 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<EntityView>> { | ||
86 | - return this.http.post<Array<EntityView>>('/api/entityViews', query, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 83 | + config?: RequestConfig): Observable<Array<EntityView>> { |
84 | + return this.http.post<Array<EntityView>>('/api/entityViews', query, defaultHttpOptionsFromConfig(config)); | ||
87 | } | 85 | } |
88 | 86 | ||
89 | } | 87 | } |
@@ -37,14 +37,14 @@ import { catchError, concatMap, expand, map, mergeMap, toArray } from 'rxjs/oper | @@ -37,14 +37,14 @@ import { catchError, concatMap, expand, map, mergeMap, toArray } from 'rxjs/oper | ||
37 | import { Customer } from '@app/shared/models/customer.model'; | 37 | import { Customer } from '@app/shared/models/customer.model'; |
38 | import { AssetService } from '@core/http/asset.service'; | 38 | import { AssetService } from '@core/http/asset.service'; |
39 | import { EntityViewService } from '@core/http/entity-view.service'; | 39 | import { EntityViewService } from '@core/http/entity-view.service'; |
40 | -import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; | ||
41 | -import { defaultHttpOptions } from '@core/http/http-utils'; | 40 | +import { AttributeScope, DataKeyType } from '@shared/models/telemetry/telemetry.models'; |
41 | +import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils'; | ||
42 | import { RuleChainService } from '@core/http/rule-chain.service'; | 42 | import { RuleChainService } from '@core/http/rule-chain.service'; |
43 | import { AliasInfo, StateParams, SubscriptionInfo } from '@core/api/widget-api.models'; | 43 | import { AliasInfo, StateParams, SubscriptionInfo } from '@core/api/widget-api.models'; |
44 | import { Datasource, DatasourceType, KeyInfo } from '@app/shared/models/widget.models'; | 44 | import { Datasource, DatasourceType, KeyInfo } from '@app/shared/models/widget.models'; |
45 | import { UtilsService } from '@core/services/utils.service'; | 45 | import { UtilsService } from '@core/services/utils.service'; |
46 | import { AliasFilterType, EntityAlias, EntityAliasFilter, EntityAliasFilterResult } from '@shared/models/alias.models'; | 46 | import { AliasFilterType, EntityAlias, EntityAliasFilter, EntityAliasFilterResult } from '@shared/models/alias.models'; |
47 | -import { EntityInfo } from '@shared/models/entity.models'; | 47 | +import { EntityInfo, ImportEntityData, ImportEntitiesResultInfo } from '@shared/models/entity.models'; |
48 | import { | 48 | import { |
49 | EntityRelationInfo, | 49 | EntityRelationInfo, |
50 | EntityRelationsQuery, | 50 | EntityRelationsQuery, |
@@ -53,9 +53,10 @@ import { | @@ -53,9 +53,10 @@ import { | ||
53 | } from '@shared/models/relation.models'; | 53 | } from '@shared/models/relation.models'; |
54 | import { EntityRelationService } from '@core/http/entity-relation.service'; | 54 | import { EntityRelationService } from '@core/http/entity-relation.service'; |
55 | import { isDefined } from '../utils'; | 55 | import { isDefined } from '../utils'; |
56 | -import { AssetSearchQuery } from '@shared/models/asset.models'; | ||
57 | -import { DeviceSearchQuery } from '@shared/models/device.models'; | 56 | +import { Asset, AssetSearchQuery } from '@shared/models/asset.models'; |
57 | +import { Device, DeviceCredentialsType, DeviceSearchQuery } from '@shared/models/device.models'; | ||
58 | import { EntityViewSearchQuery } from '@shared/models/entity-view.models'; | 58 | import { EntityViewSearchQuery } from '@shared/models/entity-view.models'; |
59 | +import { AttributeService } from '@core/http/attribute.service'; | ||
59 | 60 | ||
60 | @Injectable({ | 61 | @Injectable({ |
61 | providedIn: 'root' | 62 | providedIn: 'root' |
@@ -74,37 +75,38 @@ export class EntityService { | @@ -74,37 +75,38 @@ export class EntityService { | ||
74 | private ruleChainService: RuleChainService, | 75 | private ruleChainService: RuleChainService, |
75 | private dashboardService: DashboardService, | 76 | private dashboardService: DashboardService, |
76 | private entityRelationService: EntityRelationService, | 77 | private entityRelationService: EntityRelationService, |
78 | + private attributeService: AttributeService, | ||
77 | private utils: UtilsService | 79 | private utils: UtilsService |
78 | ) { } | 80 | ) { } |
79 | 81 | ||
80 | private getEntityObservable(entityType: EntityType, entityId: string, | 82 | private getEntityObservable(entityType: EntityType, entityId: string, |
81 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<BaseData<EntityId>> { | 83 | + config?: RequestConfig): Observable<BaseData<EntityId>> { |
82 | 84 | ||
83 | let observable: Observable<BaseData<EntityId>>; | 85 | let observable: Observable<BaseData<EntityId>>; |
84 | switch (entityType) { | 86 | switch (entityType) { |
85 | case EntityType.DEVICE: | 87 | case EntityType.DEVICE: |
86 | - observable = this.deviceService.getDevice(entityId, ignoreErrors, ignoreLoading); | 88 | + observable = this.deviceService.getDevice(entityId, config); |
87 | break; | 89 | break; |
88 | case EntityType.ASSET: | 90 | case EntityType.ASSET: |
89 | - observable = this.assetService.getAsset(entityId, ignoreErrors, ignoreLoading); | 91 | + observable = this.assetService.getAsset(entityId, config); |
90 | break; | 92 | break; |
91 | case EntityType.ENTITY_VIEW: | 93 | case EntityType.ENTITY_VIEW: |
92 | - observable = this.entityViewService.getEntityView(entityId, ignoreErrors, ignoreLoading); | 94 | + observable = this.entityViewService.getEntityView(entityId, config); |
93 | break; | 95 | break; |
94 | case EntityType.TENANT: | 96 | case EntityType.TENANT: |
95 | - observable = this.tenantService.getTenant(entityId, ignoreErrors, ignoreLoading); | 97 | + observable = this.tenantService.getTenant(entityId, config); |
96 | break; | 98 | break; |
97 | case EntityType.CUSTOMER: | 99 | case EntityType.CUSTOMER: |
98 | - observable = this.customerService.getCustomer(entityId, ignoreErrors, ignoreLoading); | 100 | + observable = this.customerService.getCustomer(entityId, config); |
99 | break; | 101 | break; |
100 | case EntityType.DASHBOARD: | 102 | case EntityType.DASHBOARD: |
101 | - observable = this.dashboardService.getDashboardInfo(entityId, ignoreErrors, ignoreLoading); | 103 | + observable = this.dashboardService.getDashboardInfo(entityId, config); |
102 | break; | 104 | break; |
103 | case EntityType.USER: | 105 | case EntityType.USER: |
104 | - observable = this.userService.getUser(entityId, ignoreErrors, ignoreLoading); | 106 | + observable = this.userService.getUser(entityId, config); |
105 | break; | 107 | break; |
106 | case EntityType.RULE_CHAIN: | 108 | case EntityType.RULE_CHAIN: |
107 | - observable = this.ruleChainService.getRuleChain(entityId, ignoreErrors, ignoreLoading); | 109 | + observable = this.ruleChainService.getRuleChain(entityId, config); |
108 | break; | 110 | break; |
109 | case EntityType.ALARM: | 111 | case EntityType.ALARM: |
110 | console.error('Get Alarm Entity is not implemented!'); | 112 | console.error('Get Alarm Entity is not implemented!'); |
@@ -113,8 +115,8 @@ export class EntityService { | @@ -113,8 +115,8 @@ export class EntityService { | ||
113 | return observable; | 115 | return observable; |
114 | } | 116 | } |
115 | public getEntity(entityType: EntityType, entityId: string, | 117 | public getEntity(entityType: EntityType, entityId: string, |
116 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<BaseData<EntityId>> { | ||
117 | - const entityObservable = this.getEntityObservable(entityType, entityId, ignoreErrors, ignoreLoading); | 118 | + config?: RequestConfig): Observable<BaseData<EntityId>> { |
119 | + const entityObservable = this.getEntityObservable(entityType, entityId, config); | ||
118 | if (entityObservable) { | 120 | if (entityObservable) { |
119 | return entityObservable; | 121 | return entityObservable; |
120 | } else { | 122 | } else { |
@@ -146,38 +148,38 @@ export class EntityService { | @@ -146,38 +148,38 @@ export class EntityService { | ||
146 | 148 | ||
147 | 149 | ||
148 | private getEntitiesObservable(entityType: EntityType, entityIds: Array<string>, | 150 | private getEntitiesObservable(entityType: EntityType, entityIds: Array<string>, |
149 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<BaseData<EntityId>>> { | 151 | + config?: RequestConfig): Observable<Array<BaseData<EntityId>>> { |
150 | let observable: Observable<Array<BaseData<EntityId>>>; | 152 | let observable: Observable<Array<BaseData<EntityId>>>; |
151 | switch (entityType) { | 153 | switch (entityType) { |
152 | case EntityType.DEVICE: | 154 | case EntityType.DEVICE: |
153 | - observable = this.deviceService.getDevices(entityIds, ignoreErrors, ignoreLoading); | 155 | + observable = this.deviceService.getDevices(entityIds, config); |
154 | break; | 156 | break; |
155 | case EntityType.ASSET: | 157 | case EntityType.ASSET: |
156 | - observable = this.assetService.getAssets(entityIds, ignoreErrors, ignoreLoading); | 158 | + observable = this.assetService.getAssets(entityIds, config); |
157 | break; | 159 | break; |
158 | case EntityType.ENTITY_VIEW: | 160 | case EntityType.ENTITY_VIEW: |
159 | observable = this.getEntitiesByIdsObservable( | 161 | observable = this.getEntitiesByIdsObservable( |
160 | - (id) => this.entityViewService.getEntityView(id, ignoreErrors, ignoreLoading), | 162 | + (id) => this.entityViewService.getEntityView(id, config), |
161 | entityIds); | 163 | entityIds); |
162 | break; | 164 | break; |
163 | case EntityType.TENANT: | 165 | case EntityType.TENANT: |
164 | observable = this.getEntitiesByIdsObservable( | 166 | observable = this.getEntitiesByIdsObservable( |
165 | - (id) => this.tenantService.getTenant(id, ignoreErrors, ignoreLoading), | 167 | + (id) => this.tenantService.getTenant(id, config), |
166 | entityIds); | 168 | entityIds); |
167 | break; | 169 | break; |
168 | case EntityType.CUSTOMER: | 170 | case EntityType.CUSTOMER: |
169 | observable = this.getEntitiesByIdsObservable( | 171 | observable = this.getEntitiesByIdsObservable( |
170 | - (id) => this.customerService.getCustomer(id, ignoreErrors, ignoreLoading), | 172 | + (id) => this.customerService.getCustomer(id, config), |
171 | entityIds); | 173 | entityIds); |
172 | break; | 174 | break; |
173 | case EntityType.DASHBOARD: | 175 | case EntityType.DASHBOARD: |
174 | observable = this.getEntitiesByIdsObservable( | 176 | observable = this.getEntitiesByIdsObservable( |
175 | - (id) => this.dashboardService.getDashboardInfo(id, ignoreErrors, ignoreLoading), | 177 | + (id) => this.dashboardService.getDashboardInfo(id, config), |
176 | entityIds); | 178 | entityIds); |
177 | break; | 179 | break; |
178 | case EntityType.USER: | 180 | case EntityType.USER: |
179 | observable = this.getEntitiesByIdsObservable( | 181 | observable = this.getEntitiesByIdsObservable( |
180 | - (id) => this.userService.getUser(id, ignoreErrors, ignoreLoading), | 182 | + (id) => this.userService.getUser(id, config), |
181 | entityIds); | 183 | entityIds); |
182 | break; | 184 | break; |
183 | case EntityType.ALARM: | 185 | case EntityType.ALARM: |
@@ -188,8 +190,8 @@ export class EntityService { | @@ -188,8 +190,8 @@ export class EntityService { | ||
188 | } | 190 | } |
189 | 191 | ||
190 | public getEntities(entityType: EntityType, entityIds: Array<string>, | 192 | public getEntities(entityType: EntityType, entityIds: Array<string>, |
191 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<BaseData<EntityId>>> { | ||
192 | - const entitiesObservable = this.getEntitiesObservable(entityType, entityIds, ignoreErrors, ignoreLoading); | 193 | + config?: RequestConfig): Observable<Array<BaseData<EntityId>>> { |
194 | + const entitiesObservable = this.getEntitiesObservable(entityType, entityIds, config); | ||
193 | if (entitiesObservable) { | 195 | if (entitiesObservable) { |
194 | return entitiesObservable; | 196 | return entitiesObservable; |
195 | } else { | 197 | } else { |
@@ -198,11 +200,10 @@ export class EntityService { | @@ -198,11 +200,10 @@ export class EntityService { | ||
198 | } | 200 | } |
199 | 201 | ||
200 | private getSingleTenantByPageLinkObservable(pageLink: PageLink, | 202 | private getSingleTenantByPageLinkObservable(pageLink: PageLink, |
201 | - ignoreErrors: boolean = false, | ||
202 | - ignoreLoading: boolean = false): Observable<PageData<Tenant>> { | 203 | + config?: RequestConfig): Observable<PageData<Tenant>> { |
203 | const authUser = getCurrentAuthUser(this.store); | 204 | const authUser = getCurrentAuthUser(this.store); |
204 | const tenantId = authUser.tenantId; | 205 | const tenantId = authUser.tenantId; |
205 | - return this.tenantService.getTenant(tenantId, ignoreErrors, ignoreLoading).pipe( | 206 | + return this.tenantService.getTenant(tenantId, config).pipe( |
206 | map((tenant) => { | 207 | map((tenant) => { |
207 | const result = { | 208 | const result = { |
208 | data: [], | 209 | data: [], |
@@ -221,11 +222,10 @@ export class EntityService { | @@ -221,11 +222,10 @@ export class EntityService { | ||
221 | } | 222 | } |
222 | 223 | ||
223 | private getSingleCustomerByPageLinkObservable(pageLink: PageLink, | 224 | private getSingleCustomerByPageLinkObservable(pageLink: PageLink, |
224 | - ignoreErrors: boolean = false, | ||
225 | - ignoreLoading: boolean = false): Observable<PageData<Customer>> { | 225 | + config?: RequestConfig): Observable<PageData<Customer>> { |
226 | const authUser = getCurrentAuthUser(this.store); | 226 | const authUser = getCurrentAuthUser(this.store); |
227 | const customerId = authUser.customerId; | 227 | const customerId = authUser.customerId; |
228 | - return this.customerService.getCustomer(customerId, ignoreErrors, ignoreLoading).pipe( | 228 | + return this.customerService.getCustomer(customerId, config).pipe( |
229 | map((customer) => { | 229 | map((customer) => { |
230 | const result = { | 230 | const result = { |
231 | data: [], | 231 | data: [], |
@@ -244,8 +244,7 @@ export class EntityService { | @@ -244,8 +244,7 @@ export class EntityService { | ||
244 | } | 244 | } |
245 | 245 | ||
246 | private getEntitiesByPageLinkObservable(entityType: EntityType, pageLink: PageLink, subType: string = '', | 246 | private getEntitiesByPageLinkObservable(entityType: EntityType, pageLink: PageLink, subType: string = '', |
247 | - ignoreErrors: boolean = false, | ||
248 | - ignoreLoading: boolean = false): Observable<PageData<BaseData<EntityId>>> { | 247 | + config?: RequestConfig): Observable<PageData<BaseData<EntityId>>> { |
249 | let entitiesObservable: Observable<PageData<BaseData<EntityId>>>; | 248 | let entitiesObservable: Observable<PageData<BaseData<EntityId>>>; |
250 | const authUser = getCurrentAuthUser(this.store); | 249 | const authUser = getCurrentAuthUser(this.store); |
251 | const customerId = authUser.customerId; | 250 | const customerId = authUser.customerId; |
@@ -253,54 +252,54 @@ export class EntityService { | @@ -253,54 +252,54 @@ export class EntityService { | ||
253 | case EntityType.DEVICE: | 252 | case EntityType.DEVICE: |
254 | pageLink.sortOrder.property = 'name'; | 253 | pageLink.sortOrder.property = 'name'; |
255 | if (authUser.authority === Authority.CUSTOMER_USER) { | 254 | if (authUser.authority === Authority.CUSTOMER_USER) { |
256 | - entitiesObservable = this.deviceService.getCustomerDeviceInfos(customerId, pageLink, subType, ignoreErrors, ignoreLoading); | 255 | + entitiesObservable = this.deviceService.getCustomerDeviceInfos(customerId, pageLink, subType, config); |
257 | } else { | 256 | } else { |
258 | - entitiesObservable = this.deviceService.getTenantDeviceInfos(pageLink, subType, ignoreErrors, ignoreLoading); | 257 | + entitiesObservable = this.deviceService.getTenantDeviceInfos(pageLink, subType, config); |
259 | } | 258 | } |
260 | break; | 259 | break; |
261 | case EntityType.ASSET: | 260 | case EntityType.ASSET: |
262 | pageLink.sortOrder.property = 'name'; | 261 | pageLink.sortOrder.property = 'name'; |
263 | if (authUser.authority === Authority.CUSTOMER_USER) { | 262 | if (authUser.authority === Authority.CUSTOMER_USER) { |
264 | - entitiesObservable = this.assetService.getCustomerAssetInfos(customerId, pageLink, subType, ignoreErrors, ignoreLoading); | 263 | + entitiesObservable = this.assetService.getCustomerAssetInfos(customerId, pageLink, subType, config); |
265 | } else { | 264 | } else { |
266 | - entitiesObservable = this.assetService.getTenantAssetInfos(pageLink, subType, ignoreErrors, ignoreLoading); | 265 | + entitiesObservable = this.assetService.getTenantAssetInfos(pageLink, subType, config); |
267 | } | 266 | } |
268 | break; | 267 | break; |
269 | case EntityType.ENTITY_VIEW: | 268 | case EntityType.ENTITY_VIEW: |
270 | pageLink.sortOrder.property = 'name'; | 269 | pageLink.sortOrder.property = 'name'; |
271 | if (authUser.authority === Authority.CUSTOMER_USER) { | 270 | if (authUser.authority === Authority.CUSTOMER_USER) { |
272 | entitiesObservable = this.entityViewService.getCustomerEntityViewInfos(customerId, pageLink, | 271 | entitiesObservable = this.entityViewService.getCustomerEntityViewInfos(customerId, pageLink, |
273 | - subType, ignoreErrors, ignoreLoading); | 272 | + subType, config); |
274 | } else { | 273 | } else { |
275 | - entitiesObservable = this.entityViewService.getTenantEntityViewInfos(pageLink, subType, ignoreErrors, ignoreLoading); | 274 | + entitiesObservable = this.entityViewService.getTenantEntityViewInfos(pageLink, subType, config); |
276 | } | 275 | } |
277 | break; | 276 | break; |
278 | case EntityType.TENANT: | 277 | case EntityType.TENANT: |
279 | pageLink.sortOrder.property = 'title'; | 278 | pageLink.sortOrder.property = 'title'; |
280 | if (authUser.authority === Authority.TENANT_ADMIN) { | 279 | if (authUser.authority === Authority.TENANT_ADMIN) { |
281 | - entitiesObservable = this.getSingleTenantByPageLinkObservable(pageLink, ignoreErrors, ignoreLoading); | 280 | + entitiesObservable = this.getSingleTenantByPageLinkObservable(pageLink, config); |
282 | } else { | 281 | } else { |
283 | - entitiesObservable = this.tenantService.getTenants(pageLink, ignoreErrors, ignoreLoading); | 282 | + entitiesObservable = this.tenantService.getTenants(pageLink, config); |
284 | } | 283 | } |
285 | break; | 284 | break; |
286 | case EntityType.CUSTOMER: | 285 | case EntityType.CUSTOMER: |
287 | pageLink.sortOrder.property = 'title'; | 286 | pageLink.sortOrder.property = 'title'; |
288 | if (authUser.authority === Authority.CUSTOMER_USER) { | 287 | if (authUser.authority === Authority.CUSTOMER_USER) { |
289 | - entitiesObservable = this.getSingleCustomerByPageLinkObservable(pageLink, ignoreErrors, ignoreLoading); | 288 | + entitiesObservable = this.getSingleCustomerByPageLinkObservable(pageLink, config); |
290 | } else { | 289 | } else { |
291 | - entitiesObservable = this.customerService.getCustomers(pageLink, ignoreErrors, ignoreLoading); | 290 | + entitiesObservable = this.customerService.getCustomers(pageLink, config); |
292 | } | 291 | } |
293 | break; | 292 | break; |
294 | case EntityType.RULE_CHAIN: | 293 | case EntityType.RULE_CHAIN: |
295 | pageLink.sortOrder.property = 'name'; | 294 | pageLink.sortOrder.property = 'name'; |
296 | - entitiesObservable = this.ruleChainService.getRuleChains(pageLink, ignoreErrors, ignoreLoading); | 295 | + entitiesObservable = this.ruleChainService.getRuleChains(pageLink, config); |
297 | break; | 296 | break; |
298 | case EntityType.DASHBOARD: | 297 | case EntityType.DASHBOARD: |
299 | pageLink.sortOrder.property = 'title'; | 298 | pageLink.sortOrder.property = 'title'; |
300 | if (authUser.authority === Authority.CUSTOMER_USER) { | 299 | if (authUser.authority === Authority.CUSTOMER_USER) { |
301 | - entitiesObservable = this.dashboardService.getCustomerDashboards(customerId, pageLink, ignoreErrors, ignoreLoading); | 300 | + entitiesObservable = this.dashboardService.getCustomerDashboards(customerId, pageLink, config); |
302 | } else { | 301 | } else { |
303 | - entitiesObservable = this.dashboardService.getTenantDashboards(pageLink, ignoreErrors, ignoreLoading); | 302 | + entitiesObservable = this.dashboardService.getTenantDashboards(pageLink, config); |
304 | } | 303 | } |
305 | break; | 304 | break; |
306 | case EntityType.USER: | 305 | case EntityType.USER: |
@@ -314,16 +313,15 @@ export class EntityService { | @@ -314,16 +313,15 @@ export class EntityService { | ||
314 | } | 313 | } |
315 | 314 | ||
316 | private getEntitiesByPageLink(entityType: EntityType, pageLink: PageLink, subType: string = '', | 315 | private getEntitiesByPageLink(entityType: EntityType, pageLink: PageLink, subType: string = '', |
317 | - ignoreErrors: boolean = false, | ||
318 | - ignoreLoading: boolean = false): Observable<Array<BaseData<EntityId>>> { | 316 | + config?: RequestConfig): Observable<Array<BaseData<EntityId>>> { |
319 | const entitiesObservable: Observable<PageData<BaseData<EntityId>>> = | 317 | const entitiesObservable: Observable<PageData<BaseData<EntityId>>> = |
320 | - this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, ignoreErrors, ignoreLoading); | 318 | + this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, config); |
321 | if (entitiesObservable) { | 319 | if (entitiesObservable) { |
322 | return entitiesObservable.pipe( | 320 | return entitiesObservable.pipe( |
323 | expand((data) => { | 321 | expand((data) => { |
324 | if (data.hasNext) { | 322 | if (data.hasNext) { |
325 | pageLink.page += 1; | 323 | pageLink.page += 1; |
326 | - return this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, ignoreErrors, ignoreLoading); | 324 | + return this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, config); |
327 | } else { | 325 | } else { |
328 | return EMPTY; | 326 | return EMPTY; |
329 | } | 327 | } |
@@ -339,19 +337,19 @@ export class EntityService { | @@ -339,19 +337,19 @@ export class EntityService { | ||
339 | 337 | ||
340 | public getEntitiesByNameFilter(entityType: EntityType, entityNameFilter: string, | 338 | public getEntitiesByNameFilter(entityType: EntityType, entityNameFilter: string, |
341 | pageSize: number, subType: string = '', | 339 | pageSize: number, subType: string = '', |
342 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<BaseData<EntityId>>> { | 340 | + config?: RequestConfig): Observable<Array<BaseData<EntityId>>> { |
343 | const pageLink = new PageLink(pageSize, 0, entityNameFilter, { | 341 | const pageLink = new PageLink(pageSize, 0, entityNameFilter, { |
344 | property: 'name', | 342 | property: 'name', |
345 | direction: Direction.ASC | 343 | direction: Direction.ASC |
346 | }); | 344 | }); |
347 | if (pageSize === -1) { // all | 345 | if (pageSize === -1) { // all |
348 | pageLink.pageSize = 100; | 346 | pageLink.pageSize = 100; |
349 | - return this.getEntitiesByPageLink(entityType, pageLink, subType, ignoreErrors, ignoreLoading).pipe( | 347 | + return this.getEntitiesByPageLink(entityType, pageLink, subType, config).pipe( |
350 | map((data) => data && data.length ? data : null) | 348 | map((data) => data && data.length ? data : null) |
351 | ); | 349 | ); |
352 | } else { | 350 | } else { |
353 | const entitiesObservable: Observable<PageData<BaseData<EntityId>>> = | 351 | const entitiesObservable: Observable<PageData<BaseData<EntityId>>> = |
354 | - this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, ignoreErrors, ignoreLoading); | 352 | + this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, config); |
355 | if (entitiesObservable) { | 353 | if (entitiesObservable) { |
356 | return entitiesObservable.pipe( | 354 | return entitiesObservable.pipe( |
357 | map((data) => data && data.data.length ? data.data : null) | 355 | map((data) => data && data.data.length ? data.data : null) |
@@ -506,7 +504,7 @@ export class EntityService { | @@ -506,7 +504,7 @@ export class EntityService { | ||
506 | } | 504 | } |
507 | 505 | ||
508 | public getEntityKeys(entityId: EntityId, query: string, type: DataKeyType, | 506 | public getEntityKeys(entityId: EntityId, query: string, type: DataKeyType, |
509 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<string>> { | 507 | + config?: RequestConfig): Observable<Array<string>> { |
510 | let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/keys/`; | 508 | let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/keys/`; |
511 | if (type === DataKeyType.timeseries) { | 509 | if (type === DataKeyType.timeseries) { |
512 | url += 'timeseries'; | 510 | url += 'timeseries'; |
@@ -514,7 +512,7 @@ export class EntityService { | @@ -514,7 +512,7 @@ export class EntityService { | ||
514 | url += 'attributes'; | 512 | url += 'attributes'; |
515 | } | 513 | } |
516 | return this.http.get<Array<string>>(url, | 514 | return this.http.get<Array<string>>(url, |
517 | - defaultHttpOptions(ignoreLoading, ignoreErrors)) | 515 | + defaultHttpOptionsFromConfig(config)) |
518 | .pipe( | 516 | .pipe( |
519 | map( | 517 | map( |
520 | (dataKeys) => { | 518 | (dataKeys) => { |
@@ -549,7 +547,7 @@ export class EntityService { | @@ -549,7 +547,7 @@ export class EntityService { | ||
549 | public createAlarmSourceFromSubscriptionInfo(subscriptionInfo: SubscriptionInfo): Observable<Datasource> { | 547 | public createAlarmSourceFromSubscriptionInfo(subscriptionInfo: SubscriptionInfo): Observable<Datasource> { |
550 | if (subscriptionInfo.entityId && subscriptionInfo.entityType) { | 548 | if (subscriptionInfo.entityId && subscriptionInfo.entityType) { |
551 | return this.getEntity(subscriptionInfo.entityType, subscriptionInfo.entityId, | 549 | return this.getEntity(subscriptionInfo.entityType, subscriptionInfo.entityId, |
552 | - true, true).pipe( | 550 | + {ignoreLoading: true, ignoreErrors: true}).pipe( |
553 | map((entity) => { | 551 | map((entity) => { |
554 | const alarmSource = this.createDatasourceFromSubscription(subscriptionInfo, entity); | 552 | const alarmSource = this.createDatasourceFromSubscription(subscriptionInfo, entity); |
555 | this.utils.generateColors([alarmSource]); | 553 | this.utils.generateColors([alarmSource]); |
@@ -594,7 +592,7 @@ export class EntityService { | @@ -594,7 +592,7 @@ export class EntityService { | ||
594 | switch (filter.type) { | 592 | switch (filter.type) { |
595 | case AliasFilterType.singleEntity: | 593 | case AliasFilterType.singleEntity: |
596 | const aliasEntityId = this.resolveAliasEntityId(filter.singleEntity.entityType, filter.singleEntity.id); | 594 | const aliasEntityId = this.resolveAliasEntityId(filter.singleEntity.entityType, filter.singleEntity.id); |
597 | - return this.getEntity(aliasEntityId.entityType as EntityType, aliasEntityId.id, true, true).pipe( | 595 | + return this.getEntity(aliasEntityId.entityType as EntityType, aliasEntityId.id, {ignoreLoading: true, ignoreErrors: true}).pipe( |
598 | map((entity) => { | 596 | map((entity) => { |
599 | result.entities = this.entitiesToEntitiesInfo([entity]); | 597 | result.entities = this.entitiesToEntitiesInfo([entity]); |
600 | return result; | 598 | return result; |
@@ -602,7 +600,7 @@ export class EntityService { | @@ -602,7 +600,7 @@ export class EntityService { | ||
602 | )); | 600 | )); |
603 | break; | 601 | break; |
604 | case AliasFilterType.entityList: | 602 | case AliasFilterType.entityList: |
605 | - return this.getEntities(filter.entityType, filter.entityList, true, true).pipe( | 603 | + return this.getEntities(filter.entityType, filter.entityList, {ignoreLoading: true, ignoreErrors: true}).pipe( |
606 | map((entities) => { | 604 | map((entities) => { |
607 | if (entities && entities.length || !failOnEmpty) { | 605 | if (entities && entities.length || !failOnEmpty) { |
608 | result.entities = this.entitiesToEntitiesInfo(entities); | 606 | result.entities = this.entitiesToEntitiesInfo(entities); |
@@ -615,7 +613,7 @@ export class EntityService { | @@ -615,7 +613,7 @@ export class EntityService { | ||
615 | break; | 613 | break; |
616 | case AliasFilterType.entityName: | 614 | case AliasFilterType.entityName: |
617 | return this.getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems, | 615 | return this.getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems, |
618 | - '', true, true).pipe( | 616 | + '', {ignoreLoading: true, ignoreErrors: true}).pipe( |
619 | map((entities) => { | 617 | map((entities) => { |
620 | if (entities && entities.length || !failOnEmpty) { | 618 | if (entities && entities.length || !failOnEmpty) { |
621 | result.entities = this.entitiesToEntitiesInfo(entities); | 619 | result.entities = this.entitiesToEntitiesInfo(entities); |
@@ -630,7 +628,7 @@ export class EntityService { | @@ -630,7 +628,7 @@ export class EntityService { | ||
630 | case AliasFilterType.stateEntity: | 628 | case AliasFilterType.stateEntity: |
631 | result.stateEntity = true; | 629 | result.stateEntity = true; |
632 | if (stateEntityId) { | 630 | if (stateEntityId) { |
633 | - return this.getEntity(stateEntityId.entityType as EntityType, stateEntityId.id, true, true).pipe( | 631 | + return this.getEntity(stateEntityId.entityType as EntityType, stateEntityId.id, {ignoreLoading: true, ignoreErrors: true}).pipe( |
634 | map((entity) => { | 632 | map((entity) => { |
635 | result.entities = this.entitiesToEntitiesInfo([entity]); | 633 | result.entities = this.entitiesToEntitiesInfo([entity]); |
636 | return result; | 634 | return result; |
@@ -642,7 +640,7 @@ export class EntityService { | @@ -642,7 +640,7 @@ export class EntityService { | ||
642 | break; | 640 | break; |
643 | case AliasFilterType.assetType: | 641 | case AliasFilterType.assetType: |
644 | return this.getEntitiesByNameFilter(EntityType.ASSET, filter.assetNameFilter, maxItems, | 642 | return this.getEntitiesByNameFilter(EntityType.ASSET, filter.assetNameFilter, maxItems, |
645 | - filter.assetType, true, true).pipe( | 643 | + filter.assetType, {ignoreLoading: true, ignoreErrors: true}).pipe( |
646 | map((entities) => { | 644 | map((entities) => { |
647 | if (entities && entities.length || !failOnEmpty) { | 645 | if (entities && entities.length || !failOnEmpty) { |
648 | result.entities = this.entitiesToEntitiesInfo(entities); | 646 | result.entities = this.entitiesToEntitiesInfo(entities); |
@@ -656,7 +654,7 @@ export class EntityService { | @@ -656,7 +654,7 @@ export class EntityService { | ||
656 | break; | 654 | break; |
657 | case AliasFilterType.deviceType: | 655 | case AliasFilterType.deviceType: |
658 | return this.getEntitiesByNameFilter(EntityType.DEVICE, filter.deviceNameFilter, maxItems, | 656 | return this.getEntitiesByNameFilter(EntityType.DEVICE, filter.deviceNameFilter, maxItems, |
659 | - filter.deviceType, true, true).pipe( | 657 | + filter.deviceType, {ignoreLoading: true, ignoreErrors: true}).pipe( |
660 | map((entities) => { | 658 | map((entities) => { |
661 | if (entities && entities.length || !failOnEmpty) { | 659 | if (entities && entities.length || !failOnEmpty) { |
662 | result.entities = this.entitiesToEntitiesInfo(entities); | 660 | result.entities = this.entitiesToEntitiesInfo(entities); |
@@ -670,7 +668,7 @@ export class EntityService { | @@ -670,7 +668,7 @@ export class EntityService { | ||
670 | break; | 668 | break; |
671 | case AliasFilterType.entityViewType: | 669 | case AliasFilterType.entityViewType: |
672 | return this.getEntitiesByNameFilter(EntityType.ENTITY_VIEW, filter.entityViewNameFilter, maxItems, | 670 | return this.getEntitiesByNameFilter(EntityType.ENTITY_VIEW, filter.entityViewNameFilter, maxItems, |
673 | - filter.entityViewType, true, true).pipe( | 671 | + filter.entityViewType, {ignoreLoading: true, ignoreErrors: true}).pipe( |
674 | map((entities) => { | 672 | map((entities) => { |
675 | if (entities && entities.length || !failOnEmpty) { | 673 | if (entities && entities.length || !failOnEmpty) { |
676 | result.entities = this.entitiesToEntitiesInfo(entities); | 674 | result.entities = this.entitiesToEntitiesInfo(entities); |
@@ -704,7 +702,7 @@ export class EntityService { | @@ -704,7 +702,7 @@ export class EntityService { | ||
704 | filters: filter.filters | 702 | filters: filter.filters |
705 | }; | 703 | }; |
706 | searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1; | 704 | searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1; |
707 | - return this.entityRelationService.findInfoByQuery(searchQuery, true, true).pipe( | 705 | + return this.entityRelationService.findInfoByQuery(searchQuery, {ignoreLoading: true, ignoreErrors: true}).pipe( |
708 | mergeMap((allRelations) => { | 706 | mergeMap((allRelations) => { |
709 | if (allRelations && allRelations.length || !failOnEmpty) { | 707 | if (allRelations && allRelations.length || !failOnEmpty) { |
710 | if (isDefined(maxItems) && maxItems > 0 && allRelations) { | 708 | if (isDefined(maxItems) && maxItems > 0 && allRelations) { |
@@ -751,15 +749,15 @@ export class EntityService { | @@ -751,15 +749,15 @@ export class EntityService { | ||
751 | if (filter.type === AliasFilterType.assetSearchQuery) { | 749 | if (filter.type === AliasFilterType.assetSearchQuery) { |
752 | const assetSearchQuery = searchQuery as AssetSearchQuery; | 750 | const assetSearchQuery = searchQuery as AssetSearchQuery; |
753 | assetSearchQuery.assetTypes = filter.assetTypes; | 751 | assetSearchQuery.assetTypes = filter.assetTypes; |
754 | - findByQueryObservable = this.assetService.findByQuery(assetSearchQuery, true, true); | 752 | + findByQueryObservable = this.assetService.findByQuery(assetSearchQuery, {ignoreLoading: true, ignoreErrors: true}); |
755 | } else if (filter.type === AliasFilterType.deviceSearchQuery) { | 753 | } else if (filter.type === AliasFilterType.deviceSearchQuery) { |
756 | const deviceSearchQuery = searchQuery as DeviceSearchQuery; | 754 | const deviceSearchQuery = searchQuery as DeviceSearchQuery; |
757 | deviceSearchQuery.deviceTypes = filter.deviceTypes; | 755 | deviceSearchQuery.deviceTypes = filter.deviceTypes; |
758 | - findByQueryObservable = this.deviceService.findByQuery(deviceSearchQuery, true, true); | 756 | + findByQueryObservable = this.deviceService.findByQuery(deviceSearchQuery, {ignoreLoading: true, ignoreErrors: true}); |
759 | } else if (filter.type === AliasFilterType.entityViewSearchQuery) { | 757 | } else if (filter.type === AliasFilterType.entityViewSearchQuery) { |
760 | const entityViewSearchQuery = searchQuery as EntityViewSearchQuery; | 758 | const entityViewSearchQuery = searchQuery as EntityViewSearchQuery; |
761 | entityViewSearchQuery.entityViewTypes = filter.entityViewTypes; | 759 | entityViewSearchQuery.entityViewTypes = filter.entityViewTypes; |
762 | - findByQueryObservable = this.entityViewService.findByQuery(entityViewSearchQuery, true, true); | 760 | + findByQueryObservable = this.entityViewService.findByQuery(entityViewSearchQuery, {ignoreLoading: true, ignoreErrors: true}); |
763 | } | 761 | } |
764 | return findByQueryObservable.pipe( | 762 | return findByQueryObservable.pipe( |
765 | map((entities) => { | 763 | map((entities) => { |
@@ -800,6 +798,115 @@ export class EntityService { | @@ -800,6 +798,115 @@ export class EntityService { | ||
800 | ); | 798 | ); |
801 | } | 799 | } |
802 | 800 | ||
801 | + public saveEntityParameters(entityType: EntityType, entityData: ImportEntityData, update: boolean, | ||
802 | + config?: RequestConfig): Observable<ImportEntitiesResultInfo> { | ||
803 | + let saveEntityObservable: Observable<BaseData<EntityId>>; | ||
804 | + switch (entityType) { | ||
805 | + case EntityType.DEVICE: | ||
806 | + const device: Device = { | ||
807 | + name: entityData.name, | ||
808 | + type: entityData.type | ||
809 | + }; | ||
810 | + saveEntityObservable = this.deviceService.saveDevice(device, config); | ||
811 | + break; | ||
812 | + case EntityType.ASSET: | ||
813 | + const asset: Asset = { | ||
814 | + name: entityData.name, | ||
815 | + type: entityData.type | ||
816 | + }; | ||
817 | + saveEntityObservable = this.assetService.saveAsset(asset, config); | ||
818 | + break; | ||
819 | + } | ||
820 | + return saveEntityObservable.pipe( | ||
821 | + mergeMap((entity) => { | ||
822 | + return this.saveEntityData(entity.id, entityData, config).pipe( | ||
823 | + map(() => { | ||
824 | + return { create: { entity: 1 } } as ImportEntitiesResultInfo; | ||
825 | + }), | ||
826 | + catchError(err => of({ error: { entity: 1 } } as ImportEntitiesResultInfo)) | ||
827 | + ); | ||
828 | + }), | ||
829 | + catchError(err => { | ||
830 | + if (update) { | ||
831 | + let findEntityObservable: Observable<BaseData<EntityId>>; | ||
832 | + switch (entityType) { | ||
833 | + case EntityType.DEVICE: | ||
834 | + findEntityObservable = this.deviceService.findByName(entityData.name, config); | ||
835 | + break; | ||
836 | + case EntityType.ASSET: | ||
837 | + findEntityObservable = this.assetService.findByName(entityData.name, config); | ||
838 | + break; | ||
839 | + } | ||
840 | + return findEntityObservable.pipe( | ||
841 | + mergeMap((entity) => { | ||
842 | + return this.saveEntityData(entity.id, entityData, config).pipe( | ||
843 | + map(() => { | ||
844 | + return { update: { entity: 1 } } as ImportEntitiesResultInfo; | ||
845 | + }), | ||
846 | + catchError(updateError => of({ error: { entity: 1 } } as ImportEntitiesResultInfo)) | ||
847 | + ); | ||
848 | + }), | ||
849 | + catchError(findErr => of({ error: { entity: 1 } } as ImportEntitiesResultInfo)) | ||
850 | + ); | ||
851 | + } else { | ||
852 | + return of({ error: { entity: 1 } } as ImportEntitiesResultInfo); | ||
853 | + } | ||
854 | + }) | ||
855 | + ); | ||
856 | + } | ||
857 | + | ||
858 | + public saveEntityData(entityId: EntityId, entityData: ImportEntityData, config?: RequestConfig): Observable<any> { | ||
859 | + const observables: Observable<string>[] = []; | ||
860 | + let observable: Observable<string>; | ||
861 | + if (entityData.accessToken && entityData.accessToken !== '') { | ||
862 | + observable = this.deviceService.getDeviceCredentials(entityId.id, false, config).pipe( | ||
863 | + mergeMap((credentials) => { | ||
864 | + credentials.credentialsId = entityData.accessToken; | ||
865 | + credentials.credentialsType = DeviceCredentialsType.ACCESS_TOKEN; | ||
866 | + credentials.credentialsValue = null; | ||
867 | + return this.deviceService.saveDeviceCredentials(credentials, config).pipe( | ||
868 | + map(() => 'ok'), | ||
869 | + catchError(err => of('error')) | ||
870 | + ); | ||
871 | + }) | ||
872 | + ); | ||
873 | + observables.push(observable); | ||
874 | + } | ||
875 | + if (entityData.attributes.shared && entityData.attributes.shared.length) { | ||
876 | + observable = this.attributeService.saveEntityAttributes(entityId, AttributeScope.SHARED_SCOPE, | ||
877 | + entityData.attributes.shared, config).pipe( | ||
878 | + map(() => 'ok'), | ||
879 | + catchError(err => of('error')) | ||
880 | + ); | ||
881 | + observables.push(observable); | ||
882 | + } | ||
883 | + if (entityData.attributes.server && entityData.attributes.server.length) { | ||
884 | + observable = this.attributeService.saveEntityAttributes(entityId, AttributeScope.SERVER_SCOPE, | ||
885 | + entityData.attributes.server, config).pipe( | ||
886 | + map(() => 'ok'), | ||
887 | + catchError(err => of('error')) | ||
888 | + ); | ||
889 | + observables.push(observable); | ||
890 | + } | ||
891 | + if (entityData.timeseries && entityData.timeseries.length) { | ||
892 | + observable = this.attributeService.saveEntityTimeseries(entityId, 'time', entityData.timeseries, config).pipe( | ||
893 | + map(() => 'ok'), | ||
894 | + catchError(err => of('error')) | ||
895 | + ); | ||
896 | + observables.push(observable); | ||
897 | + } | ||
898 | + return forkJoin(observables).pipe( | ||
899 | + map((response) => { | ||
900 | + const hasError = response.filter((status) => status === 'error').length > 0; | ||
901 | + if (hasError) { | ||
902 | + throw Error(); | ||
903 | + } else { | ||
904 | + return response; | ||
905 | + } | ||
906 | + }) | ||
907 | + ); | ||
908 | + } | ||
909 | + | ||
803 | private entitiesToEntitiesInfo(entities: Array<BaseData<EntityId>>): Array<EntityInfo> { | 910 | private entitiesToEntitiesInfo(entities: Array<BaseData<EntityId>>): Array<EntityInfo> { |
804 | const entitiesInfo = []; | 911 | const entitiesInfo = []; |
805 | if (entities) { | 912 | if (entities) { |
@@ -836,7 +943,7 @@ export class EntityService { | @@ -836,7 +943,7 @@ export class EntityService { | ||
836 | 943 | ||
837 | private entityRelationInfoToEntityInfo(entityRelationInfo: EntityRelationInfo, direction: EntitySearchDirection): Observable<EntityInfo> { | 944 | private entityRelationInfoToEntityInfo(entityRelationInfo: EntityRelationInfo, direction: EntitySearchDirection): Observable<EntityInfo> { |
838 | const entityId = direction === EntitySearchDirection.FROM ? entityRelationInfo.to : entityRelationInfo.from; | 945 | const entityId = direction === EntitySearchDirection.FROM ? entityRelationInfo.to : entityRelationInfo.from; |
839 | - return this.getEntity(entityId.entityType as EntityType, entityId.id, true, true).pipe( | 946 | + return this.getEntity(entityId.entityType as EntityType, entityId.id, {ignoreLoading: true, ignoreErrors: true}).pipe( |
840 | map((entity) => { | 947 | map((entity) => { |
841 | return this.entityToEntityInfo(entity); | 948 | return this.entityToEntityInfo(entity); |
842 | }) | 949 | }) |
@@ -907,7 +1014,7 @@ export class EntityService { | @@ -907,7 +1014,7 @@ export class EntityService { | ||
907 | return of([entity]); | 1014 | return of([entity]); |
908 | } else { | 1015 | } else { |
909 | return this.getEntity(subscriptionInfo.entityType, subscriptionInfo.entityId, | 1016 | return this.getEntity(subscriptionInfo.entityType, subscriptionInfo.entityId, |
910 | - true, true).pipe( | 1017 | + {ignoreLoading: true, ignoreErrors: true}).pipe( |
911 | map((entity) => [entity]), | 1018 | map((entity) => [entity]), |
912 | catchError(e => of([])) | 1019 | catchError(e => of([])) |
913 | ); | 1020 | ); |
@@ -916,12 +1023,13 @@ export class EntityService { | @@ -916,12 +1023,13 @@ export class EntityService { | ||
916 | let entitiesObservable: Observable<Array<BaseData<EntityId>>>; | 1023 | let entitiesObservable: Observable<Array<BaseData<EntityId>>>; |
917 | if (subscriptionInfo.entityName) { | 1024 | if (subscriptionInfo.entityName) { |
918 | entitiesObservable = this.getEntitiesByNameFilter(subscriptionInfo.entityType, subscriptionInfo.entityName, | 1025 | entitiesObservable = this.getEntitiesByNameFilter(subscriptionInfo.entityType, subscriptionInfo.entityName, |
919 | - 1, null, true, true); | 1026 | + 1, null, {ignoreLoading: true, ignoreErrors: true}); |
920 | } else if (subscriptionInfo.entityNamePrefix) { | 1027 | } else if (subscriptionInfo.entityNamePrefix) { |
921 | entitiesObservable = this.getEntitiesByNameFilter(subscriptionInfo.entityType, subscriptionInfo.entityNamePrefix, | 1028 | entitiesObservable = this.getEntitiesByNameFilter(subscriptionInfo.entityType, subscriptionInfo.entityNamePrefix, |
922 | - 100, null, true, true); | 1029 | + 100, null, {ignoreLoading: true, ignoreErrors: true}); |
923 | } else if (subscriptionInfo.entityIds) { | 1030 | } else if (subscriptionInfo.entityIds) { |
924 | - entitiesObservable = this.getEntities(subscriptionInfo.entityType, subscriptionInfo.entityIds, true, true); | 1031 | + entitiesObservable = this.getEntities(subscriptionInfo.entityType, subscriptionInfo.entityIds, |
1032 | + {ignoreLoading: true, ignoreErrors: true}); | ||
925 | } | 1033 | } |
926 | return entitiesObservable.pipe( | 1034 | return entitiesObservable.pipe( |
927 | catchError(e => of([])) | 1035 | catchError(e => of([])) |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable } from 'rxjs/index'; | 19 | import { Observable } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { TimePageLink } from '@shared/models/page/page-link'; | 21 | import { TimePageLink } from '@shared/models/page/page-link'; |
@@ -33,9 +33,9 @@ export class EventService { | @@ -33,9 +33,9 @@ export class EventService { | ||
33 | ) { } | 33 | ) { } |
34 | 34 | ||
35 | public getEvents(entityId: EntityId, eventType: EventType | DebugEventType, tenantId: string, pageLink: TimePageLink, | 35 | public getEvents(entityId: EntityId, eventType: EventType | DebugEventType, tenantId: string, pageLink: TimePageLink, |
36 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<Event>> { | 36 | + config?: RequestConfig): Observable<PageData<Event>> { |
37 | return this.http.get<PageData<Event>>(`/api/events/${entityId.entityType}/${entityId.id}/${eventType}` + | 37 | return this.http.get<PageData<Event>>(`/api/events/${entityId.entityType}/${entityId.id}/${eventType}` + |
38 | `${pageLink.toQuery()}&tenantId=${tenantId}`, | 38 | `${pageLink.toQuery()}&tenantId=${tenantId}`, |
39 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 39 | + defaultHttpOptionsFromConfig(config)); |
40 | } | 40 | } |
41 | } | 41 | } |
@@ -18,6 +18,19 @@ import { InterceptorHttpParams } from '../interceptors/interceptor-http-params'; | @@ -18,6 +18,19 @@ import { InterceptorHttpParams } from '../interceptors/interceptor-http-params'; | ||
18 | import { HttpHeaders } from '@angular/common/http'; | 18 | import { HttpHeaders } from '@angular/common/http'; |
19 | import { InterceptorConfig } from '../interceptors/interceptor-config'; | 19 | import { InterceptorConfig } from '../interceptors/interceptor-config'; |
20 | 20 | ||
21 | +export interface RequestConfig { | ||
22 | + ignoreLoading?: boolean; | ||
23 | + ignoreErrors?: boolean; | ||
24 | + resendRequest?: boolean; | ||
25 | +} | ||
26 | + | ||
27 | +export function defaultHttpOptionsFromConfig(config?: RequestConfig) { | ||
28 | + if (!config) { | ||
29 | + config = {}; | ||
30 | + } | ||
31 | + return defaultHttpOptions(config.ignoreLoading, config.ignoreErrors, config.resendRequest); | ||
32 | +} | ||
33 | + | ||
21 | export function defaultHttpOptions(ignoreLoading: boolean = false, | 34 | export function defaultHttpOptions(ignoreLoading: boolean = false, |
22 | ignoreErrors: boolean = false, | 35 | ignoreErrors: boolean = false, |
23 | resendRequest: boolean = false) { | 36 | resendRequest: boolean = false) { |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import {Injectable} from '@angular/core'; | 17 | import {Injectable} from '@angular/core'; |
18 | -import {defaultHttpOptions} from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import {Observable} from 'rxjs/index'; | 19 | import {Observable} from 'rxjs/index'; |
20 | import {HttpClient} from '@angular/common/http'; | 20 | import {HttpClient} from '@angular/common/http'; |
21 | import {PageLink} from '@shared/models/page/page-link'; | 21 | import {PageLink} from '@shared/models/page/page-link'; |
@@ -31,26 +31,25 @@ export class RuleChainService { | @@ -31,26 +31,25 @@ export class RuleChainService { | ||
31 | private http: HttpClient | 31 | private http: HttpClient |
32 | ) { } | 32 | ) { } |
33 | 33 | ||
34 | - public getRuleChains(pageLink: PageLink, ignoreErrors: boolean = false, | ||
35 | - ignoreLoading: boolean = false): Observable<PageData<RuleChain>> { | 34 | + public getRuleChains(pageLink: PageLink, config?: RequestConfig): Observable<PageData<RuleChain>> { |
36 | return this.http.get<PageData<RuleChain>>(`/api/ruleChains${pageLink.toQuery()}`, | 35 | return this.http.get<PageData<RuleChain>>(`/api/ruleChains${pageLink.toQuery()}`, |
37 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 36 | + defaultHttpOptionsFromConfig(config)); |
38 | } | 37 | } |
39 | 38 | ||
40 | - public getRuleChain(ruleChainId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<RuleChain> { | ||
41 | - return this.http.get<RuleChain>(`/api/ruleChain/${ruleChainId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 39 | + public getRuleChain(ruleChainId: string, config?: RequestConfig): Observable<RuleChain> { |
40 | + return this.http.get<RuleChain>(`/api/ruleChain/${ruleChainId}`, defaultHttpOptionsFromConfig(config)); | ||
42 | } | 41 | } |
43 | 42 | ||
44 | - public saveRuleChain(ruleChain: RuleChain, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<RuleChain> { | ||
45 | - return this.http.post<RuleChain>('/api/ruleChain', ruleChain, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 43 | + public saveRuleChain(ruleChain: RuleChain, config?: RequestConfig): Observable<RuleChain> { |
44 | + return this.http.post<RuleChain>('/api/ruleChain', ruleChain, defaultHttpOptionsFromConfig(config)); | ||
46 | } | 45 | } |
47 | 46 | ||
48 | - public deleteRuleChain(ruleChainId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
49 | - return this.http.delete(`/api/ruleChain/${ruleChainId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 47 | + public deleteRuleChain(ruleChainId: string, config?: RequestConfig) { |
48 | + return this.http.delete(`/api/ruleChain/${ruleChainId}`, defaultHttpOptionsFromConfig(config)); | ||
50 | } | 49 | } |
51 | 50 | ||
52 | - public setRootRuleChain(ruleChainId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<RuleChain> { | ||
53 | - return this.http.post<RuleChain>(`/api/ruleChain/${ruleChainId}/root`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 51 | + public setRootRuleChain(ruleChainId: string, config?: RequestConfig): Observable<RuleChain> { |
52 | + return this.http.post<RuleChain>(`/api/ruleChain/${ruleChainId}/root`, null, defaultHttpOptionsFromConfig(config)); | ||
54 | } | 53 | } |
55 | 54 | ||
56 | } | 55 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable } from 'rxjs/index'; | 19 | import { Observable } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { PageLink } from '@shared/models/page/page-link'; | 21 | import { PageLink } from '@shared/models/page/page-link'; |
@@ -31,20 +31,20 @@ export class TenantService { | @@ -31,20 +31,20 @@ export class TenantService { | ||
31 | private http: HttpClient | 31 | private http: HttpClient |
32 | ) { } | 32 | ) { } |
33 | 33 | ||
34 | - public getTenants(pageLink: PageLink, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<Tenant>> { | ||
35 | - return this.http.get<PageData<Tenant>>(`/api/tenants${pageLink.toQuery()}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 34 | + public getTenants(pageLink: PageLink, config?: RequestConfig): Observable<PageData<Tenant>> { |
35 | + return this.http.get<PageData<Tenant>>(`/api/tenants${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); | ||
36 | } | 36 | } |
37 | 37 | ||
38 | - public getTenant(tenantId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Tenant> { | ||
39 | - return this.http.get<Tenant>(`/api/tenant/${tenantId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 38 | + public getTenant(tenantId: string, config?: RequestConfig): Observable<Tenant> { |
39 | + return this.http.get<Tenant>(`/api/tenant/${tenantId}`, defaultHttpOptionsFromConfig(config)); | ||
40 | } | 40 | } |
41 | 41 | ||
42 | - public saveTenant(tenant: Tenant, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Tenant> { | ||
43 | - return this.http.post<Tenant>('/api/tenant', tenant, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 42 | + public saveTenant(tenant: Tenant, config?: RequestConfig): Observable<Tenant> { |
43 | + return this.http.post<Tenant>('/api/tenant', tenant, defaultHttpOptionsFromConfig(config)); | ||
44 | } | 44 | } |
45 | 45 | ||
46 | - public deleteTenant(tenantId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
47 | - return this.http.delete(`/api/tenant/${tenantId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 46 | + public deleteTenant(tenantId: string, config?: RequestConfig) { |
47 | + return this.http.delete(`/api/tenant/${tenantId}`, defaultHttpOptionsFromConfig(config)); | ||
48 | } | 48 | } |
49 | 49 | ||
50 | } | 50 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { User } from '../../shared/models/user.model'; | 19 | import { User } from '../../shared/models/user.model'; |
20 | import { Observable } from 'rxjs/index'; | 20 | import { Observable } from 'rxjs/index'; |
21 | import { HttpClient, HttpResponse } from '@angular/common/http'; | 21 | import { HttpClient, HttpResponse } from '@angular/common/http'; |
@@ -33,39 +33,39 @@ export class UserService { | @@ -33,39 +33,39 @@ export class UserService { | ||
33 | ) { } | 33 | ) { } |
34 | 34 | ||
35 | public getTenantAdmins(tenantId: string, pageLink: PageLink, | 35 | public getTenantAdmins(tenantId: string, pageLink: PageLink, |
36 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<User>> { | 36 | + config?: RequestConfig): Observable<PageData<User>> { |
37 | return this.http.get<PageData<User>>(`/api/tenant/${tenantId}/users${pageLink.toQuery()}`, | 37 | return this.http.get<PageData<User>>(`/api/tenant/${tenantId}/users${pageLink.toQuery()}`, |
38 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 38 | + defaultHttpOptionsFromConfig(config)); |
39 | } | 39 | } |
40 | 40 | ||
41 | public getCustomerUsers(customerId: string, pageLink: PageLink, | 41 | public getCustomerUsers(customerId: string, pageLink: PageLink, |
42 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<PageData<User>> { | 42 | + config?: RequestConfig): Observable<PageData<User>> { |
43 | return this.http.get<PageData<User>>(`/api/customer/${customerId}/users${pageLink.toQuery()}`, | 43 | return this.http.get<PageData<User>>(`/api/customer/${customerId}/users${pageLink.toQuery()}`, |
44 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 44 | + defaultHttpOptionsFromConfig(config)); |
45 | } | 45 | } |
46 | 46 | ||
47 | - public getUser(userId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<User> { | ||
48 | - return this.http.get<User>(`/api/user/${userId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 47 | + public getUser(userId: string, config?: RequestConfig): Observable<User> { |
48 | + return this.http.get<User>(`/api/user/${userId}`, defaultHttpOptionsFromConfig(config)); | ||
49 | } | 49 | } |
50 | 50 | ||
51 | public saveUser(user: User, sendActivationMail: boolean = false, | 51 | public saveUser(user: User, sendActivationMail: boolean = false, |
52 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<User> { | 52 | + config?: RequestConfig): Observable<User> { |
53 | let url = '/api/user'; | 53 | let url = '/api/user'; |
54 | url += '?sendActivationMail=' + sendActivationMail; | 54 | url += '?sendActivationMail=' + sendActivationMail; |
55 | - return this.http.post<User>(url, user, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 55 | + return this.http.post<User>(url, user, defaultHttpOptionsFromConfig(config)); |
56 | } | 56 | } |
57 | 57 | ||
58 | - public deleteUser(userId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
59 | - return this.http.delete(`/api/user/${userId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 58 | + public deleteUser(userId: string, config?: RequestConfig) { |
59 | + return this.http.delete(`/api/user/${userId}`, defaultHttpOptionsFromConfig(config)); | ||
60 | } | 60 | } |
61 | 61 | ||
62 | - public getActivationLink(userId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<string> { | 62 | + public getActivationLink(userId: string, config?: RequestConfig): Observable<string> { |
63 | return this.http.get(`/api/user/${userId}/activationLink`, | 63 | return this.http.get(`/api/user/${userId}/activationLink`, |
64 | - {...{responseType: 'text'}, ...defaultHttpOptions(ignoreLoading, ignoreErrors)}); | 64 | + {...{responseType: 'text'}, ...defaultHttpOptionsFromConfig(config)}); |
65 | } | 65 | } |
66 | 66 | ||
67 | - public sendActivationEmail(email: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
68 | - return this.http.post(`/api/user/sendActivationMail?email=${email}`, null, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 67 | + public sendActivationEmail(email: string, config?: RequestConfig) { |
68 | + return this.http.post(`/api/user/sendActivationMail?email=${email}`, null, defaultHttpOptionsFromConfig(config)); | ||
69 | } | 69 | } |
70 | 70 | ||
71 | } | 71 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Injectable } from '@angular/core'; | 17 | import { Injectable } from '@angular/core'; |
18 | -import { defaultHttpOptions } from './http-utils'; | 18 | +import { defaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
19 | import { Observable, Subject, of, ReplaySubject } from 'rxjs/index'; | 19 | import { Observable, Subject, of, ReplaySubject } from 'rxjs/index'; |
20 | import { HttpClient } from '@angular/common/http'; | 20 | import { HttpClient } from '@angular/common/http'; |
21 | import { PageLink } from '@shared/models/page/page-link'; | 21 | import { PageLink } from '@shared/models/page/page-link'; |
@@ -57,53 +57,49 @@ export class WidgetService { | @@ -57,53 +57,49 @@ export class WidgetService { | ||
57 | ); | 57 | ); |
58 | } | 58 | } |
59 | 59 | ||
60 | - public getAllWidgetsBundles(ignoreErrors: boolean = false, | ||
61 | - ignoreLoading: boolean = false): Observable<Array<WidgetsBundle>> { | ||
62 | - return this.loadWidgetsBundleCache(ignoreErrors, ignoreLoading).pipe( | 60 | + public getAllWidgetsBundles(config?: RequestConfig): Observable<Array<WidgetsBundle>> { |
61 | + return this.loadWidgetsBundleCache(config).pipe( | ||
63 | map(() => this.allWidgetsBundles) | 62 | map(() => this.allWidgetsBundles) |
64 | ); | 63 | ); |
65 | } | 64 | } |
66 | 65 | ||
67 | - public getSystemWidgetsBundles(ignoreErrors: boolean = false, | ||
68 | - ignoreLoading: boolean = false): Observable<Array<WidgetsBundle>> { | ||
69 | - return this.loadWidgetsBundleCache(ignoreErrors, ignoreLoading).pipe( | 66 | + public getSystemWidgetsBundles(config?: RequestConfig): Observable<Array<WidgetsBundle>> { |
67 | + return this.loadWidgetsBundleCache(config).pipe( | ||
70 | map(() => this.systemWidgetsBundles) | 68 | map(() => this.systemWidgetsBundles) |
71 | ); | 69 | ); |
72 | } | 70 | } |
73 | 71 | ||
74 | - public getTenantWidgetsBundles(ignoreErrors: boolean = false, | ||
75 | - ignoreLoading: boolean = false): Observable<Array<WidgetsBundle>> { | ||
76 | - return this.loadWidgetsBundleCache(ignoreErrors, ignoreLoading).pipe( | 72 | + public getTenantWidgetsBundles(config?: RequestConfig): Observable<Array<WidgetsBundle>> { |
73 | + return this.loadWidgetsBundleCache(config).pipe( | ||
77 | map(() => this.tenantWidgetsBundles) | 74 | map(() => this.tenantWidgetsBundles) |
78 | ); | 75 | ); |
79 | } | 76 | } |
80 | 77 | ||
81 | - public getWidgetBundles(pageLink: PageLink, ignoreErrors: boolean = false, | ||
82 | - ignoreLoading: boolean = false): Observable<PageData<WidgetsBundle>> { | 78 | + public getWidgetBundles(pageLink: PageLink, config?: RequestConfig): Observable<PageData<WidgetsBundle>> { |
83 | return this.http.get<PageData<WidgetsBundle>>(`/api/widgetsBundles${pageLink.toQuery()}`, | 79 | return this.http.get<PageData<WidgetsBundle>>(`/api/widgetsBundles${pageLink.toQuery()}`, |
84 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 80 | + defaultHttpOptionsFromConfig(config)); |
85 | } | 81 | } |
86 | 82 | ||
87 | public getWidgetsBundle(widgetsBundleId: string, | 83 | public getWidgetsBundle(widgetsBundleId: string, |
88 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<WidgetsBundle> { | ||
89 | - return this.http.get<WidgetsBundle>(`/api/widgetsBundle/${widgetsBundleId}`, defaultHttpOptions(ignoreLoading, ignoreErrors)); | 84 | + config?: RequestConfig): Observable<WidgetsBundle> { |
85 | + return this.http.get<WidgetsBundle>(`/api/widgetsBundle/${widgetsBundleId}`, defaultHttpOptionsFromConfig(config)); | ||
90 | } | 86 | } |
91 | 87 | ||
92 | public saveWidgetsBundle(widgetsBundle: WidgetsBundle, | 88 | public saveWidgetsBundle(widgetsBundle: WidgetsBundle, |
93 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<WidgetsBundle> { | 89 | + config?: RequestConfig): Observable<WidgetsBundle> { |
94 | return this.http.post<WidgetsBundle>('/api/widgetsBundle', widgetsBundle, | 90 | return this.http.post<WidgetsBundle>('/api/widgetsBundle', widgetsBundle, |
95 | - defaultHttpOptions(ignoreLoading, ignoreErrors)).pipe( | 91 | + defaultHttpOptionsFromConfig(config)).pipe( |
96 | tap(() => { | 92 | tap(() => { |
97 | this.invalidateWidgetsBundleCache(); | 93 | this.invalidateWidgetsBundleCache(); |
98 | }) | 94 | }) |
99 | ); | 95 | ); |
100 | } | 96 | } |
101 | 97 | ||
102 | - public deleteWidgetsBundle(widgetsBundleId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
103 | - return this.getWidgetsBundle(widgetsBundleId, ignoreErrors, ignoreLoading).pipe( | 98 | + public deleteWidgetsBundle(widgetsBundleId: string, config?: RequestConfig) { |
99 | + return this.getWidgetsBundle(widgetsBundleId, config).pipe( | ||
104 | mergeMap((widgetsBundle) => { | 100 | mergeMap((widgetsBundle) => { |
105 | return this.http.delete(`/api/widgetsBundle/${widgetsBundleId}`, | 101 | return this.http.delete(`/api/widgetsBundle/${widgetsBundleId}`, |
106 | - defaultHttpOptions(ignoreLoading, ignoreErrors)).pipe( | 102 | + defaultHttpOptionsFromConfig(config)).pipe( |
107 | tap(() => { | 103 | tap(() => { |
108 | this.invalidateWidgetsBundleCache(); | 104 | this.invalidateWidgetsBundleCache(); |
109 | this.widgetsBundleDeletedSubject.next(widgetsBundle); | 105 | this.widgetsBundleDeletedSubject.next(widgetsBundle); |
@@ -114,14 +110,14 @@ export class WidgetService { | @@ -114,14 +110,14 @@ export class WidgetService { | ||
114 | } | 110 | } |
115 | 111 | ||
116 | public getBundleWidgetTypes(bundleAlias: string, isSystem: boolean, | 112 | public getBundleWidgetTypes(bundleAlias: string, isSystem: boolean, |
117 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<WidgetType>> { | 113 | + config?: RequestConfig): Observable<Array<WidgetType>> { |
118 | return this.http.get<Array<WidgetType>>(`/api/widgetTypes?isSystem=${isSystem}&bundleAlias=${bundleAlias}`, | 114 | return this.http.get<Array<WidgetType>>(`/api/widgetTypes?isSystem=${isSystem}&bundleAlias=${bundleAlias}`, |
119 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 115 | + defaultHttpOptionsFromConfig(config)); |
120 | } | 116 | } |
121 | 117 | ||
122 | public loadBundleLibraryWidgets(bundleAlias: string, isSystem: boolean, | 118 | public loadBundleLibraryWidgets(bundleAlias: string, isSystem: boolean, |
123 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<Widget>> { | ||
124 | - return this.getBundleWidgetTypes(bundleAlias, isSystem, ignoreErrors, ignoreLoading).pipe( | 119 | + config?: RequestConfig): Observable<Array<Widget>> { |
120 | + return this.getBundleWidgetTypes(bundleAlias, isSystem, config).pipe( | ||
125 | map((types) => { | 121 | map((types) => { |
126 | types = types.sort((a, b) => { | 122 | types = types.sort((a, b) => { |
127 | let result = widgetType[b.descriptor.type].localeCompare(widgetType[a.descriptor.type]); | 123 | let result = widgetType[b.descriptor.type].localeCompare(widgetType[a.descriptor.type]); |
@@ -173,38 +169,38 @@ export class WidgetService { | @@ -173,38 +169,38 @@ export class WidgetService { | ||
173 | } | 169 | } |
174 | 170 | ||
175 | public getWidgetType(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean, | 171 | public getWidgetType(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean, |
176 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<WidgetType> { | 172 | + config?: RequestConfig): Observable<WidgetType> { |
177 | return this.http.get<WidgetType>(`/api/widgetType?isSystem=${isSystem}&bundleAlias=${bundleAlias}&alias=${widgetTypeAlias}`, | 173 | return this.http.get<WidgetType>(`/api/widgetType?isSystem=${isSystem}&bundleAlias=${bundleAlias}&alias=${widgetTypeAlias}`, |
178 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 174 | + defaultHttpOptionsFromConfig(config)); |
179 | } | 175 | } |
180 | 176 | ||
181 | public saveWidgetType(widgetInfo: WidgetInfo, | 177 | public saveWidgetType(widgetInfo: WidgetInfo, |
182 | id: WidgetTypeId, | 178 | id: WidgetTypeId, |
183 | bundleAlias: string, | 179 | bundleAlias: string, |
184 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<WidgetType> { | 180 | + config?: RequestConfig): Observable<WidgetType> { |
185 | const widgetTypeInstance = toWidgetType(widgetInfo, id, undefined, bundleAlias); | 181 | const widgetTypeInstance = toWidgetType(widgetInfo, id, undefined, bundleAlias); |
186 | return this.http.post<WidgetType>('/api/widgetType', widgetTypeInstance, | 182 | return this.http.post<WidgetType>('/api/widgetType', widgetTypeInstance, |
187 | - defaultHttpOptions(ignoreLoading, ignoreErrors)).pipe( | 183 | + defaultHttpOptionsFromConfig(config)).pipe( |
188 | tap((savedWidgetType) => { | 184 | tap((savedWidgetType) => { |
189 | this.widgetTypeUpdatedSubject.next(savedWidgetType); | 185 | this.widgetTypeUpdatedSubject.next(savedWidgetType); |
190 | })); | 186 | })); |
191 | } | 187 | } |
192 | 188 | ||
193 | public saveImportedWidgetType(widgetTypeInstance: WidgetType, | 189 | public saveImportedWidgetType(widgetTypeInstance: WidgetType, |
194 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<WidgetType> { | 190 | + config?: RequestConfig): Observable<WidgetType> { |
195 | return this.http.post<WidgetType>('/api/widgetType', widgetTypeInstance, | 191 | return this.http.post<WidgetType>('/api/widgetType', widgetTypeInstance, |
196 | - defaultHttpOptions(ignoreLoading, ignoreErrors)).pipe( | 192 | + defaultHttpOptionsFromConfig(config)).pipe( |
197 | tap((savedWidgetType) => { | 193 | tap((savedWidgetType) => { |
198 | this.widgetTypeUpdatedSubject.next(savedWidgetType); | 194 | this.widgetTypeUpdatedSubject.next(savedWidgetType); |
199 | })); | 195 | })); |
200 | } | 196 | } |
201 | 197 | ||
202 | public deleteWidgetType(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean, | 198 | public deleteWidgetType(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean, |
203 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false) { | ||
204 | - return this.getWidgetType(bundleAlias, widgetTypeAlias, isSystem, ignoreErrors, ignoreLoading).pipe( | 199 | + config?: RequestConfig) { |
200 | + return this.getWidgetType(bundleAlias, widgetTypeAlias, isSystem, config).pipe( | ||
205 | mergeMap((widgetTypeInstance) => { | 201 | mergeMap((widgetTypeInstance) => { |
206 | return this.http.delete(`/api/widgetType/${widgetTypeInstance.id.id}`, | 202 | return this.http.delete(`/api/widgetType/${widgetTypeInstance.id.id}`, |
207 | - defaultHttpOptions(ignoreLoading, ignoreErrors)).pipe( | 203 | + defaultHttpOptionsFromConfig(config)).pipe( |
208 | tap(() => { | 204 | tap(() => { |
209 | this.widgetTypeUpdatedSubject.next(widgetTypeInstance); | 205 | this.widgetTypeUpdatedSubject.next(widgetTypeInstance); |
210 | }) | 206 | }) |
@@ -214,16 +210,16 @@ export class WidgetService { | @@ -214,16 +210,16 @@ export class WidgetService { | ||
214 | } | 210 | } |
215 | 211 | ||
216 | public getWidgetTypeById(widgetTypeId: string, | 212 | public getWidgetTypeById(widgetTypeId: string, |
217 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<WidgetType> { | 213 | + config?: RequestConfig): Observable<WidgetType> { |
218 | return this.http.get<WidgetType>(`/api/widgetType/${widgetTypeId}`, | 214 | return this.http.get<WidgetType>(`/api/widgetType/${widgetTypeId}`, |
219 | - defaultHttpOptions(ignoreLoading, ignoreErrors)); | 215 | + defaultHttpOptionsFromConfig(config)); |
220 | } | 216 | } |
221 | 217 | ||
222 | public getWidgetTemplate(widgetTypeParam: widgetType, | 218 | public getWidgetTemplate(widgetTypeParam: widgetType, |
223 | - ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<WidgetInfo> { | 219 | + config?: RequestConfig): Observable<WidgetInfo> { |
224 | const templateWidgetType = widgetTypesData.get(widgetTypeParam); | 220 | const templateWidgetType = widgetTypesData.get(widgetTypeParam); |
225 | return this.getWidgetType(templateWidgetType.template.bundleAlias, templateWidgetType.template.alias, true, | 221 | return this.getWidgetType(templateWidgetType.template.bundleAlias, templateWidgetType.template.alias, true, |
226 | - ignoreErrors, ignoreLoading).pipe( | 222 | + config).pipe( |
227 | map((result) => { | 223 | map((result) => { |
228 | const widgetInfo = toWidgetInfo(result); | 224 | const widgetInfo = toWidgetInfo(result); |
229 | widgetInfo.alias = undefined; | 225 | widgetInfo.alias = undefined; |
@@ -240,11 +236,11 @@ export class WidgetService { | @@ -240,11 +236,11 @@ export class WidgetService { | ||
240 | return this.widgetsBundleDeletedSubject.asObservable(); | 236 | return this.widgetsBundleDeletedSubject.asObservable(); |
241 | } | 237 | } |
242 | 238 | ||
243 | - private loadWidgetsBundleCache(ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<any> { | 239 | + private loadWidgetsBundleCache(config?: RequestConfig): Observable<any> { |
244 | if (!this.allWidgetsBundles) { | 240 | if (!this.allWidgetsBundles) { |
245 | const loadWidgetsBundleCacheSubject = new ReplaySubject(); | 241 | const loadWidgetsBundleCacheSubject = new ReplaySubject(); |
246 | this.http.get<Array<WidgetsBundle>>('/api/widgetsBundles', | 242 | this.http.get<Array<WidgetsBundle>>('/api/widgetsBundles', |
247 | - defaultHttpOptions(ignoreLoading, ignoreErrors)).subscribe( | 243 | + defaultHttpOptionsFromConfig(config)).subscribe( |
248 | (allWidgetsBundles) => { | 244 | (allWidgetsBundles) => { |
249 | this.allWidgetsBundles = allWidgetsBundles; | 245 | this.allWidgetsBundles = allWidgetsBundles; |
250 | this.systemWidgetsBundles = new Array<WidgetsBundle>(); | 246 | this.systemWidgetsBundles = new Array<WidgetsBundle>(); |
@@ -19,17 +19,21 @@ import { UtilsService } from '@core/services/utils.service'; | @@ -19,17 +19,21 @@ import { UtilsService } from '@core/services/utils.service'; | ||
19 | import { TimeService } from '@core/services/time.service'; | 19 | import { TimeService } from '@core/services/time.service'; |
20 | import { | 20 | import { |
21 | Dashboard, | 21 | Dashboard, |
22 | - DashboardLayout, | ||
23 | - DashboardStateLayouts, | ||
24 | - DashboardState, | ||
25 | DashboardConfiguration, | 22 | DashboardConfiguration, |
23 | + DashboardLayout, | ||
24 | + DashboardLayoutId, | ||
26 | DashboardLayoutInfo, | 25 | DashboardLayoutInfo, |
27 | - DashboardLayoutsInfo, DashboardLayoutId, WidgetLayout, GridSettings | 26 | + DashboardLayoutsInfo, |
27 | + DashboardState, | ||
28 | + DashboardStateLayouts, | ||
29 | + GridSettings, | ||
30 | + WidgetLayout | ||
28 | } from '@shared/models/dashboard.models'; | 31 | } from '@shared/models/dashboard.models'; |
29 | -import { isUndefined, isDefined, isString } from '@core/utils'; | ||
30 | -import { DatasourceType, Widget, Datasource } from '@app/shared/models/widget.models'; | 32 | +import { isDefined, isString, isUndefined } from '@core/utils'; |
33 | +import { Datasource, DatasourceType, Widget } from '@app/shared/models/widget.models'; | ||
31 | import { EntityType } from '@shared/models/entity-type.models'; | 34 | import { EntityType } from '@shared/models/entity-type.models'; |
32 | -import { EntityAlias, AliasFilterType } from '@app/shared/models/alias.models'; | 35 | +import { AliasFilterType, EntityAlias, EntityAliasFilter } from '@app/shared/models/alias.models'; |
36 | +import { EntityId } from '@app/shared/models/id/entity-id'; | ||
33 | 37 | ||
34 | @Injectable({ | 38 | @Injectable({ |
35 | providedIn: 'root' | 39 | providedIn: 'root' |
@@ -207,7 +211,7 @@ export class DashboardUtilsService { | @@ -207,7 +211,7 @@ export class DashboardUtilsService { | ||
207 | delete datasource.deviceAliasId; | 211 | delete datasource.deviceAliasId; |
208 | } | 212 | } |
209 | }); | 213 | }); |
210 | - // TODO: Temp workaround | 214 | + // Temp workaround |
211 | if (widget.isSystemType && widget.bundleAlias === 'charts' && widget.typeAlias === 'timeseries') { | 215 | if (widget.isSystemType && widget.bundleAlias === 'charts' && widget.typeAlias === 'timeseries') { |
212 | widget.typeAlias = 'basic_timeseries'; | 216 | widget.typeAlias = 'basic_timeseries'; |
213 | } | 217 | } |
@@ -245,6 +249,14 @@ export class DashboardUtilsService { | @@ -245,6 +249,14 @@ export class DashboardUtilsService { | ||
245 | }; | 249 | }; |
246 | } | 250 | } |
247 | 251 | ||
252 | + public createSingleEntityFilter(entityId: EntityId): EntityAliasFilter { | ||
253 | + return { | ||
254 | + type: AliasFilterType.singleEntity, | ||
255 | + singleEntity: entityId, | ||
256 | + resolveMultiple: false | ||
257 | + }; | ||
258 | + } | ||
259 | + | ||
248 | private validateAndUpdateState(state: DashboardState) { | 260 | private validateAndUpdateState(state: DashboardState) { |
249 | if (!state.layouts) { | 261 | if (!state.layouts) { |
250 | state.layouts = this.createDefaultLayouts(); | 262 | state.layouts = this.createDefaultLayouts(); |
@@ -30,7 +30,6 @@ import { | @@ -30,7 +30,6 @@ import { | ||
30 | MaterialIconsDialogComponent, | 30 | MaterialIconsDialogComponent, |
31 | MaterialIconsDialogData | 31 | MaterialIconsDialogData |
32 | } from '@shared/components/dialog/material-icons-dialog.component'; | 32 | } from '@shared/components/dialog/material-icons-dialog.component'; |
33 | -import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service'; | ||
34 | 33 | ||
35 | @Injectable( | 34 | @Injectable( |
36 | { | 35 | { |
@@ -42,7 +41,6 @@ export class DialogService { | @@ -42,7 +41,6 @@ export class DialogService { | ||
42 | constructor( | 41 | constructor( |
43 | private translate: TranslateService, | 42 | private translate: TranslateService, |
44 | private authService: AuthService, | 43 | private authService: AuthService, |
45 | - private dynamicComponentFactoryService: DynamicComponentFactoryService, | ||
46 | public dialog: MatDialog | 44 | public dialog: MatDialog |
47 | ) { | 45 | ) { |
48 | } | 46 | } |
@@ -396,4 +396,42 @@ export class UtilsService { | @@ -396,4 +396,42 @@ export class UtilsService { | ||
396 | this.window.performance.now() : Date.now(); | 396 | this.window.performance.now() : Date.now(); |
397 | } | 397 | } |
398 | 398 | ||
399 | + public getQueryParam(name: string): string { | ||
400 | + const url = this.window.location.href; | ||
401 | + name = name.replace(/[\[\]]/g, '\\$&'); | ||
402 | + const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'); | ||
403 | + const results = regex.exec(url); | ||
404 | + if (!results) { | ||
405 | + return null; | ||
406 | + } | ||
407 | + if (!results[2]) { | ||
408 | + return ''; | ||
409 | + } | ||
410 | + return decodeURIComponent(results[2].replace(/\+/g, ' ')); | ||
411 | + } | ||
412 | + | ||
413 | + public updateQueryParam(name: string, value: string | null) { | ||
414 | + const baseUrl = [this.window.location.protocol, '//', this.window.location.host, this.window.location.pathname].join(''); | ||
415 | + const urlQueryString = this.window.location.search; | ||
416 | + let newParam = ''; | ||
417 | + let params = ''; | ||
418 | + if (value !== null) { | ||
419 | + newParam = name + '=' + value; | ||
420 | + } | ||
421 | + if (urlQueryString) { | ||
422 | + const keyRegex = new RegExp('([\?&])' + name + '[^&]*'); | ||
423 | + if (urlQueryString.match(keyRegex) !== null) { | ||
424 | + if (newParam) { | ||
425 | + newParam = '$1' + newParam; | ||
426 | + } | ||
427 | + params = urlQueryString.replace(keyRegex, newParam); | ||
428 | + } else if (newParam) { | ||
429 | + params = urlQueryString + '&' + newParam; | ||
430 | + } | ||
431 | + } else if (newParam) { | ||
432 | + params = '?' + newParam; | ||
433 | + } | ||
434 | + this.window.history.replaceState({}, '', baseUrl + params); | ||
435 | + } | ||
436 | + | ||
399 | } | 437 | } |
@@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { ActivationEnd, Router } from '@angular/router'; | 17 | +import { ActivationEnd, ActivationStart, Router } from '@angular/router'; |
18 | import { Injectable } from '@angular/core'; | 18 | import { Injectable } from '@angular/core'; |
19 | import { select, Store } from '@ngrx/store'; | 19 | import { select, Store } from '@ngrx/store'; |
20 | import { Actions, Effect, ofType } from '@ngrx/effects'; | 20 | import { Actions, Effect, ofType } from '@ngrx/effects'; |
@@ -39,6 +39,10 @@ import { AppState } from '@app/core/core.state'; | @@ -39,6 +39,10 @@ import { AppState } from '@app/core/core.state'; | ||
39 | import { LocalStorageService } from '@app/core/local-storage/local-storage.service'; | 39 | import { LocalStorageService } from '@app/core/local-storage/local-storage.service'; |
40 | import { TitleService } from '@app/core/services/title.service'; | 40 | import { TitleService } from '@app/core/services/title.service'; |
41 | import { updateUserLang } from '@app/core/settings/settings.utils'; | 41 | import { updateUserLang } from '@app/core/settings/settings.utils'; |
42 | +import { AuthService } from '@core/auth/auth.service'; | ||
43 | +import { UtilsService } from '@core/services/utils.service'; | ||
44 | +import { getCurrentAuthUser } from '@core/auth/auth.selectors'; | ||
45 | +import { ActionAuthUpdateLastPublicDashboardId } from '../auth/auth.actions'; | ||
42 | 46 | ||
43 | export const SETTINGS_KEY = 'SETTINGS'; | 47 | export const SETTINGS_KEY = 'SETTINGS'; |
44 | 48 | ||
@@ -47,6 +51,8 @@ export class SettingsEffects { | @@ -47,6 +51,8 @@ export class SettingsEffects { | ||
47 | constructor( | 51 | constructor( |
48 | private actions$: Actions<SettingsActions>, | 52 | private actions$: Actions<SettingsActions>, |
49 | private store: Store<AppState>, | 53 | private store: Store<AppState>, |
54 | + private authService: AuthService, | ||
55 | + private utils: UtilsService, | ||
50 | private router: Router, | 56 | private router: Router, |
51 | private localStorageService: LocalStorageService, | 57 | private localStorageService: LocalStorageService, |
52 | private titleService: TitleService, | 58 | private titleService: TitleService, |
@@ -85,4 +91,20 @@ export class SettingsEffects { | @@ -85,4 +91,20 @@ export class SettingsEffects { | ||
85 | ); | 91 | ); |
86 | }) | 92 | }) |
87 | ); | 93 | ); |
94 | + | ||
95 | + @Effect({dispatch: false}) | ||
96 | + setPublicId = merge( | ||
97 | + this.router.events.pipe(filter(event => event instanceof ActivationEnd)) | ||
98 | + ).pipe( | ||
99 | + tap((event) => { | ||
100 | + const authUser = getCurrentAuthUser(this.store); | ||
101 | + const snapshot = (event as ActivationEnd).snapshot; | ||
102 | + if (authUser && authUser.isPublic && snapshot.url && snapshot.url.length | ||
103 | + && snapshot.url[0].path === 'dashboard') { | ||
104 | + this.utils.updateQueryParam('publicId', authUser.sub); | ||
105 | + this.store.dispatch(new ActionAuthUpdateLastPublicDashboardId( | ||
106 | + { lastPublicDashboardId: snapshot.params.dashboardId})); | ||
107 | + } | ||
108 | + }) | ||
109 | + ); | ||
88 | } | 110 | } |
ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.html
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<form #addWidgetForm="ngForm" [formGroup]="addWidgetFormGroup" (ngSubmit)="add()" style="min-width: 400px;"> | ||
19 | + <mat-toolbar fxLayout="row" color="primary"> | ||
20 | + <h2 translate>attribute.add-widget-to-dashboard</h2> | ||
21 | + <span fxFlex></span> | ||
22 | + <button mat-button mat-icon-button | ||
23 | + (click)="cancel()" | ||
24 | + type="button"> | ||
25 | + <mat-icon class="material-icons">close</mat-icon> | ||
26 | + </button> | ||
27 | + </mat-toolbar> | ||
28 | + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> | ||
29 | + </mat-progress-bar> | ||
30 | + <div mat-dialog-content fxLayout="column"> | ||
31 | + <fieldset [disabled]="isLoading$ | async"> | ||
32 | + <mat-radio-group formControlName="addToDashboardType"> | ||
33 | + <mat-radio-button [value]="0" color="primary"> | ||
34 | + <section fxLayout="column" style="width: 300px;"> | ||
35 | + <span translate>dashboard.select-existing</span> | ||
36 | + <tb-dashboard-autocomplete formControlName="dashboardId" | ||
37 | + [required]="addWidgetFormGroup.get('addToDashboardType').value === 0" | ||
38 | + [selectFirstDashboard]="false"> | ||
39 | + </tb-dashboard-autocomplete> | ||
40 | + </section> | ||
41 | + </mat-radio-button> | ||
42 | + <mat-radio-button [value]="1" color="primary"> | ||
43 | + <section fxLayout="column" style="width: 300px;"> | ||
44 | + <span translate>dashboard.create-new</span> | ||
45 | + <mat-form-field class="mat-block"> | ||
46 | + <mat-label translate>dashboard.new-dashboard-title</mat-label> | ||
47 | + <input matInput formControlName="newDashboardTitle" | ||
48 | + [required]="addWidgetFormGroup.get('addToDashboardType').value === 1"> | ||
49 | + <mat-error *ngIf="addWidgetFormGroup.get('newDashboardTitle').hasError('required')"> | ||
50 | + {{ 'dashboard.title-required' | translate }} | ||
51 | + </mat-error> | ||
52 | + </mat-form-field> | ||
53 | + </section> | ||
54 | + </mat-radio-button> | ||
55 | + </mat-radio-group> | ||
56 | + </fieldset> | ||
57 | + </div> | ||
58 | + <div mat-dialog-actions fxLayout="row"> | ||
59 | + <span fxFlex></span> | ||
60 | + <mat-checkbox formControlName="openDashboard" | ||
61 | + style="margin-bottom: 0px; padding-right: 20px;"> | ||
62 | + {{ 'dashboard.open-dashboard' | translate }} | ||
63 | + </mat-checkbox> | ||
64 | + <button mat-button mat-raised-button color="primary" | ||
65 | + type="submit" | ||
66 | + [disabled]="(isLoading$ | async) || addWidgetFormGroup.invalid || !addWidgetFormGroup.dirty"> | ||
67 | + {{ 'action.add' | translate }} | ||
68 | + </button> | ||
69 | + <button mat-button color="primary" | ||
70 | + style="margin-right: 20px;" | ||
71 | + type="button" | ||
72 | + [disabled]="(isLoading$ | async)" | ||
73 | + (click)="cancel()" cdkFocusInitial> | ||
74 | + {{ 'action.cancel' | translate }} | ||
75 | + </button> | ||
76 | + </div> | ||
77 | +</form> |
ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.scss
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2019 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +:host ::ng-deep { | ||
18 | + mat-radio-button { | ||
19 | + display: block; | ||
20 | + margin-bottom: 16px; | ||
21 | + .mat-radio-label { | ||
22 | + width: 100%; | ||
23 | + align-items: start; | ||
24 | + .mat-radio-label-content { | ||
25 | + width: 100%; | ||
26 | + } | ||
27 | + } | ||
28 | + } | ||
29 | +} |
ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.ts
0 → 100644
1 | +/// | ||
2 | +/// Copyright © 2016-2019 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; | ||
18 | +import { ErrorStateMatcher, MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; | ||
19 | +import { Store } from '@ngrx/store'; | ||
20 | +import { AppState } from '@core/core.state'; | ||
21 | +import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; | ||
22 | +import { Router } from '@angular/router'; | ||
23 | +import { DialogComponent } from '@app/shared/components/dialog.component'; | ||
24 | +import { UtilsService } from '@core/services/utils.service'; | ||
25 | +import { TranslateService } from '@ngx-translate/core'; | ||
26 | +import { | ||
27 | + DashboardLayoutId, | ||
28 | + DashboardSettings, | ||
29 | + GridSettings, | ||
30 | + StateControllerId, | ||
31 | + Dashboard | ||
32 | +} from '@app/shared/models/dashboard.models'; | ||
33 | +import { isUndefined, objToBase64 } from '@core/utils'; | ||
34 | +import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; | ||
35 | +import { EntityId } from '@app/shared/models/id/entity-id'; | ||
36 | +import { Widget } from '@app/shared/models/widget.models'; | ||
37 | +import { DashboardService } from '@core/http/dashboard.service'; | ||
38 | +import { forkJoin, Observable, of } from 'rxjs'; | ||
39 | +import { SelectTargetLayoutDialogComponent } from '@home/pages/dashboard/layout/select-target-layout-dialog.component'; | ||
40 | +import { MatDialog } from '@angular/material/dialog'; | ||
41 | +import { | ||
42 | + SelectTargetStateDialogComponent, | ||
43 | + SelectTargetStateDialogData | ||
44 | +} from '@home/pages/dashboard/states/select-target-state-dialog.component'; | ||
45 | +import { mergeMap, map } from 'rxjs/operators'; | ||
46 | +import { AliasesInfo } from '@shared/models/alias.models'; | ||
47 | +import { ItemBufferService } from '@core/services/item-buffer.service'; | ||
48 | +import { StateObject } from '@core/api/widget-api.models'; | ||
49 | + | ||
50 | +export interface AddWidgetToDashboardDialogData { | ||
51 | + entityId: EntityId; | ||
52 | + entityName: string; | ||
53 | + widget: Widget; | ||
54 | +} | ||
55 | + | ||
56 | +@Component({ | ||
57 | + selector: 'tb-add-widget-to-dashboard-dialog', | ||
58 | + templateUrl: './add-widget-to-dashboard-dialog.component.html', | ||
59 | + providers: [{provide: ErrorStateMatcher, useExisting: AddWidgetToDashboardDialogComponent}], | ||
60 | + styleUrls: ['./add-widget-to-dashboard-dialog.component.scss'] | ||
61 | +}) | ||
62 | +export class AddWidgetToDashboardDialogComponent extends | ||
63 | + DialogComponent<AddWidgetToDashboardDialogComponent, void> | ||
64 | + implements OnInit, ErrorStateMatcher { | ||
65 | + | ||
66 | + addWidgetFormGroup: FormGroup; | ||
67 | + | ||
68 | + submitted = false; | ||
69 | + | ||
70 | + constructor(protected store: Store<AppState>, | ||
71 | + protected router: Router, | ||
72 | + @Inject(MAT_DIALOG_DATA) public data: AddWidgetToDashboardDialogData, | ||
73 | + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, | ||
74 | + public dialogRef: MatDialogRef<AddWidgetToDashboardDialogComponent, void>, | ||
75 | + private fb: FormBuilder, | ||
76 | + private utils: UtilsService, | ||
77 | + private dashboardUtils: DashboardUtilsService, | ||
78 | + private dashboardService: DashboardService, | ||
79 | + private itembuffer: ItemBufferService, | ||
80 | + private dialog: MatDialog) { | ||
81 | + super(store, router, dialogRef); | ||
82 | + | ||
83 | + this.addWidgetFormGroup = this.fb.group( | ||
84 | + { | ||
85 | + addToDashboardType: [0, []], | ||
86 | + dashboardId: [null, [Validators.required]], | ||
87 | + newDashboardTitle: [{value: null, disabled: true}, []], | ||
88 | + openDashboard: [false, []] | ||
89 | + } | ||
90 | + ); | ||
91 | + | ||
92 | + this.addWidgetFormGroup.get('addToDashboardType').valueChanges.subscribe( | ||
93 | + (addToDashboardType: number) => { | ||
94 | + if (addToDashboardType === 0) { | ||
95 | + this.addWidgetFormGroup.get('dashboardId').setValidators([Validators.required]); | ||
96 | + this.addWidgetFormGroup.get('dashboardId').enable(); | ||
97 | + this.addWidgetFormGroup.get('newDashboardTitle').setValidators([]); | ||
98 | + this.addWidgetFormGroup.get('newDashboardTitle').disable(); | ||
99 | + this.addWidgetFormGroup.get('dashboardId').updateValueAndValidity(); | ||
100 | + this.addWidgetFormGroup.get('newDashboardTitle').updateValueAndValidity(); | ||
101 | + } else { | ||
102 | + this.addWidgetFormGroup.get('dashboardId').setValidators([]); | ||
103 | + this.addWidgetFormGroup.get('dashboardId').disable(); | ||
104 | + this.addWidgetFormGroup.get('newDashboardTitle').setValidators([Validators.required]); | ||
105 | + this.addWidgetFormGroup.get('newDashboardTitle').enable(); | ||
106 | + this.addWidgetFormGroup.get('dashboardId').updateValueAndValidity(); | ||
107 | + this.addWidgetFormGroup.get('newDashboardTitle').updateValueAndValidity(); | ||
108 | + } | ||
109 | + } | ||
110 | + ); | ||
111 | + } | ||
112 | + | ||
113 | + ngOnInit(): void { | ||
114 | + } | ||
115 | + | ||
116 | + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { | ||
117 | + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); | ||
118 | + const customErrorState = !!(control && control.invalid && this.submitted); | ||
119 | + return originalErrorState || customErrorState; | ||
120 | + } | ||
121 | + | ||
122 | + cancel(): void { | ||
123 | + this.dialogRef.close(null); | ||
124 | + } | ||
125 | + | ||
126 | + add(): void { | ||
127 | + this.submitted = true; | ||
128 | + const addToDashboardType: number = this.addWidgetFormGroup.get('addToDashboardType').value; | ||
129 | + if (addToDashboardType === 0) { | ||
130 | + const dashboardId: string = this.addWidgetFormGroup.get('dashboardId').value; | ||
131 | + this.dashboardService.getDashboard(dashboardId).pipe( | ||
132 | + mergeMap((dashboard) => { | ||
133 | + dashboard = this.dashboardUtils.validateAndUpdateDashboard(dashboard); | ||
134 | + return this.selectTargetState(dashboard).pipe( | ||
135 | + mergeMap((targetState) => { | ||
136 | + return forkJoin([of(dashboard), of(targetState), this.selectTargetLayout(dashboard, targetState)]); | ||
137 | + }) | ||
138 | + ); | ||
139 | + }) | ||
140 | + ).subscribe((res) => { | ||
141 | + this.addWidgetToDashboard(res[0], res[1], res[2]); | ||
142 | + }); | ||
143 | + } else { | ||
144 | + const dashboardTitle: string = this.addWidgetFormGroup.get('newDashboardTitle').value; | ||
145 | + const newDashboard: Dashboard = { | ||
146 | + title: dashboardTitle | ||
147 | + }; | ||
148 | + this.addWidgetToDashboard(newDashboard, 'default', 'main'); | ||
149 | + } | ||
150 | + } | ||
151 | + | ||
152 | + private selectTargetState(dashboard: Dashboard): Observable<string> { | ||
153 | + const states = dashboard.configuration.states; | ||
154 | + const stateIds = Object.keys(states); | ||
155 | + if (stateIds.length > 1) { | ||
156 | + return this.dialog.open<SelectTargetStateDialogComponent, SelectTargetStateDialogData, | ||
157 | + string>(SelectTargetStateDialogComponent, { | ||
158 | + disableClose: true, | ||
159 | + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | ||
160 | + data: { | ||
161 | + states | ||
162 | + } | ||
163 | + }).afterClosed(); | ||
164 | + } else { | ||
165 | + return of(stateIds[0]); | ||
166 | + } | ||
167 | + } | ||
168 | + | ||
169 | + private selectTargetLayout(dashboard: Dashboard, targetState: string): Observable<DashboardLayoutId> { | ||
170 | + const layouts = dashboard.configuration.states[targetState].layouts; | ||
171 | + const layoutIds = Object.keys(layouts); | ||
172 | + if (layoutIds.length > 1) { | ||
173 | + return this.dialog.open<SelectTargetLayoutDialogComponent, any, | ||
174 | + DashboardLayoutId>(SelectTargetLayoutDialogComponent, { | ||
175 | + disableClose: true, | ||
176 | + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] | ||
177 | + }).afterClosed(); | ||
178 | + } else { | ||
179 | + return of(layoutIds[0] as DashboardLayoutId); | ||
180 | + } | ||
181 | + } | ||
182 | + | ||
183 | + private addWidgetToDashboard(dashboard: Dashboard, targetState: string, targetLayout: DashboardLayoutId) { | ||
184 | + const aliasesInfo: AliasesInfo = { | ||
185 | + datasourceAliases: {}, | ||
186 | + targetDeviceAliases: {} | ||
187 | + }; | ||
188 | + aliasesInfo.datasourceAliases[0] = { | ||
189 | + alias: this.data.entityName, | ||
190 | + filter: this.dashboardUtils.createSingleEntityFilter(this.data.entityId) | ||
191 | + }; | ||
192 | + this.itembuffer.addWidgetToDashboard(dashboard, targetState, | ||
193 | + targetLayout, this.data.widget, aliasesInfo, null, | ||
194 | + 48, null, -1, -1).pipe( | ||
195 | + mergeMap((theDashboard) => { | ||
196 | + return this.dashboardService.saveDashboard(theDashboard); | ||
197 | + }) | ||
198 | + ).subscribe( | ||
199 | + (theDashboard) => { | ||
200 | + const openDashboard: boolean = this.addWidgetFormGroup.get('openDashboard').value; | ||
201 | + this.dialogRef.close(); | ||
202 | + if (openDashboard) { | ||
203 | + let url; | ||
204 | + const stateIds = Object.keys(dashboard.configuration.states); | ||
205 | + const stateIndex = stateIds.indexOf(targetState); | ||
206 | + if (stateIndex > 0) { | ||
207 | + const stateObject: StateObject = { | ||
208 | + id: targetState, | ||
209 | + params: {} | ||
210 | + }; | ||
211 | + const state = objToBase64([ stateObject ]); | ||
212 | + url = `/dashboards/${theDashboard.id.id}?state=${state}`; | ||
213 | + } else { | ||
214 | + url = `/dashboards/${theDashboard.id.id}`; | ||
215 | + } | ||
216 | + const urlTree = this.router.parseUrl(url); | ||
217 | + this.router.navigateByUrl(url); | ||
218 | + } | ||
219 | + } | ||
220 | + ); | ||
221 | + } | ||
222 | +} |
@@ -104,20 +104,26 @@ | @@ -104,20 +104,26 @@ | ||
104 | </div> | 104 | </div> |
105 | </mat-toolbar> | 105 | </mat-toolbar> |
106 | <mat-toolbar class="mat-table-toolbar" color="primary" [fxShow]="mode === 'widget'"> | 106 | <mat-toolbar class="mat-table-toolbar" color="primary" [fxShow]="mode === 'widget'"> |
107 | - <div class="mat-toolbar-tools"> | 107 | + <div class="mat-toolbar-tools" fxLayoutGap="8px"> |
108 | <div fxFlex fxLayout="row" fxLayoutAlign="start"> | 108 | <div fxFlex fxLayout="row" fxLayoutAlign="start"> |
109 | <span class="tb-details-subtitle">{{ 'widgets-bundle.current' | translate }}</span> | 109 | <span class="tb-details-subtitle">{{ 'widgets-bundle.current' | translate }}</span> |
110 | - <span fxFlex>TODO:</span> | 110 | + <tb-widgets-bundle-select fxFlexOffset="5" |
111 | + fxFlex | ||
112 | + [selectFirstBundle]="false" | ||
113 | + [selectBundleAlias]="selectedWidgetsBundleAlias" | ||
114 | + [(ngModel)]="widgetsBundle" | ||
115 | + (ngModelChange)="onWidgetsBundleChanged($event)"> | ||
116 | + </tb-widgets-bundle-select> | ||
111 | </div> | 117 | </div> |
112 | - <!--button mat-button mat-raised-button | 118 | + <button mat-button mat-raised-button [fxShow]="widgetsList.length > 0" |
113 | color="accent" | 119 | color="accent" |
114 | [disabled]="isLoading$ | async" | 120 | [disabled]="isLoading$ | async" |
115 | - matTooltip="{{ 'attribute.show-on-widget' | translate }}" | 121 | + matTooltip="{{ 'attribute.add-to-dashboard' | translate }}" |
116 | matTooltipPosition="above" | 122 | matTooltipPosition="above" |
117 | - (click)="enterWidgetMode()"> | ||
118 | - <mat-icon>now_widgets</mat-icon> | ||
119 | - <span translate>attribute.show-on-widget</span> | ||
120 | - </button--> | 123 | + (click)="addWidgetToDashboard()"> |
124 | + <mat-icon>dashboard</mat-icon> | ||
125 | + <span translate>attribute.add-to-dashboard</span> | ||
126 | + </button> | ||
121 | <button mat-button mat-icon-button | 127 | <button mat-button mat-icon-button |
122 | [disabled]="isLoading$ | async" | 128 | [disabled]="isLoading$ | async" |
123 | matTooltip="{{ 'action.close' | translate }}" | 129 | matTooltip="{{ 'action.close' | translate }}" |
@@ -186,8 +192,61 @@ | @@ -186,8 +192,61 @@ | ||
186 | [pageIndex]="pageLink.page" | 192 | [pageIndex]="pageLink.page" |
187 | [pageSize]="pageLink.pageSize" | 193 | [pageSize]="pageLink.pageSize" |
188 | [pageSizeOptions]="[10, 20, 30]"></mat-paginator> | 194 | [pageSizeOptions]="[10, 20, 30]"></mat-paginator> |
189 | - <div fxFlex [fxShow]="mode === 'widget'"> | ||
190 | - Coming soon! | ||
191 | - </div> | 195 | + <ngx-hm-carousel fxFlex *ngIf="mode === 'widget' && widgetsList.length > 0" |
196 | + #carousel | ||
197 | + [(ngModel)]="widgetsCarouselIndex" | ||
198 | + (ngModelChange)="onWidgetsCarouselIndexChanged($event)" | ||
199 | + [data]="widgetsList" | ||
200 | + [infinite]="false" | ||
201 | + class="carousel c-accent"> | ||
202 | + <section ngx-hm-carousel-container class="content"> | ||
203 | + <article class="item cursor-pointer" | ||
204 | + ngx-hm-carousel-item | ||
205 | + *ngFor="let widgets of widgetsList"> | ||
206 | + <tb-dashboard class="tb-absolute-fill" | ||
207 | + [aliasController]="aliasController" | ||
208 | + [widgets]="widgets" | ||
209 | + [columns]="20" | ||
210 | + [isEdit]="false" | ||
211 | + [isMobileDisabled]="true" | ||
212 | + [isEditActionEnabled]="false" | ||
213 | + [isRemoveActionEnabled]="false"> | ||
214 | + </tb-dashboard> | ||
215 | + </article> | ||
216 | + </section> | ||
217 | + | ||
218 | + <ng-template #carouselPrev> | ||
219 | + <button mat-button mat-icon-button *ngIf="widgetsCarouselIndex > 0" | ||
220 | + matTooltip="{{ 'attribute.prev-widget' | translate }}" | ||
221 | + matTooltipPosition="above"> | ||
222 | + <mat-icon>keyboard_arrow_left</mat-icon> | ||
223 | + </button> | ||
224 | + </ng-template> | ||
225 | + <ng-template #carouselNext> | ||
226 | + <button mat-button mat-icon-button *ngIf="widgetsCarouselIndex < widgetsList.length - 1" | ||
227 | + matTooltip="{{ 'attribute.next-widget' | translate }}" | ||
228 | + matTooltipPosition="above"> | ||
229 | + <mat-icon>keyboard_arrow_right</mat-icon> | ||
230 | + </button> | ||
231 | + </ng-template> | ||
232 | + | ||
233 | + <ng-template #carouselDot let-model> | ||
234 | + <div class="ball" | ||
235 | + [class.visible]="model.index === model.currentIndex"></div> | ||
236 | + </ng-template> | ||
237 | + | ||
238 | + </ngx-hm-carousel> | ||
239 | + <span translate *ngIf="mode === 'widget' && widgetsLoaded && | ||
240 | + widgetsList.length === 0 && | ||
241 | + widgetsBundle" | ||
242 | + fxLayoutAlign="center center" | ||
243 | + fxFlex | ||
244 | + style="text-transform: uppercase; display: flex;" | ||
245 | + class="mat-headline">widgets-bundle.empty</span> | ||
246 | + <span translate *ngIf="mode === 'widget' && !widgetsBundle" | ||
247 | + fxLayoutAlign="center center" | ||
248 | + fxFlex | ||
249 | + style="text-transform: uppercase; display: flex;" | ||
250 | + class="mat-headline">widget.select-widgets-bundle</span> | ||
192 | </div> | 251 | </div> |
193 | </div> | 252 | </div> |
@@ -60,4 +60,36 @@ | @@ -60,4 +60,36 @@ | ||
60 | color: #757575 | 60 | color: #757575 |
61 | } | 61 | } |
62 | } | 62 | } |
63 | + | ||
64 | + .carousel { | ||
65 | + .aniT { | ||
66 | + transition: all 1s linear; | ||
67 | + } | ||
68 | + | ||
69 | + .transition { | ||
70 | + transition: all 0.3s ease-in-out !important; | ||
71 | + } | ||
72 | + .content { | ||
73 | + display: flex; | ||
74 | + height: 100%; | ||
75 | + .item { | ||
76 | + position: relative; | ||
77 | + } | ||
78 | + } | ||
79 | + .direction { | ||
80 | + width: 60px; | ||
81 | + } | ||
82 | + .ball { | ||
83 | + width: 10px; | ||
84 | + height: 10px; | ||
85 | + border-radius: 50%; | ||
86 | + background: black; | ||
87 | + border: 2px solid; | ||
88 | + opacity: 0.5; | ||
89 | + | ||
90 | + &.visible { | ||
91 | + opacity: 1; | ||
92 | + } | ||
93 | + } | ||
94 | + } | ||
63 | } | 95 | } |
@@ -19,7 +19,7 @@ import { | @@ -19,7 +19,7 @@ import { | ||
19 | ChangeDetectionStrategy, | 19 | ChangeDetectionStrategy, |
20 | Component, | 20 | Component, |
21 | ElementRef, | 21 | ElementRef, |
22 | - Input, | 22 | + Input, NgZone, |
23 | OnInit, | 23 | OnInit, |
24 | ViewChild, | 24 | ViewChild, |
25 | ViewContainerRef | 25 | ViewContainerRef |
@@ -40,7 +40,9 @@ import { EntityId } from '@shared/models/id/entity-id'; | @@ -40,7 +40,9 @@ import { EntityId } from '@shared/models/id/entity-id'; | ||
40 | import { | 40 | import { |
41 | AttributeData, | 41 | AttributeData, |
42 | AttributeScope, | 42 | AttributeScope, |
43 | - isClientSideTelemetryType, LatestTelemetry, | 43 | + DataKeyType, |
44 | + isClientSideTelemetryType, | ||
45 | + LatestTelemetry, | ||
44 | TelemetryType, | 46 | TelemetryType, |
45 | telemetryTypeTranslations | 47 | telemetryTypeTranslations |
46 | } from '@shared/models/telemetry/telemetry.models'; | 48 | } from '@shared/models/telemetry/telemetry.models'; |
@@ -48,13 +50,11 @@ import { AttributeDatasource } from '@home/models/datasource/attribute-datasourc | @@ -48,13 +50,11 @@ import { AttributeDatasource } from '@home/models/datasource/attribute-datasourc | ||
48 | import { AttributeService } from '@app/core/http/attribute.service'; | 50 | import { AttributeService } from '@app/core/http/attribute.service'; |
49 | import { EntityType } from '@shared/models/entity-type.models'; | 51 | import { EntityType } from '@shared/models/entity-type.models'; |
50 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; | 52 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
51 | -import { RelationDialogComponent, RelationDialogData } from '@home/components/relation/relation-dialog.component'; | ||
52 | import { | 53 | import { |
53 | AddAttributeDialogComponent, | 54 | AddAttributeDialogComponent, |
54 | AddAttributeDialogData | 55 | AddAttributeDialogData |
55 | } from '@home/components/attribute/add-attribute-dialog.component'; | 56 | } from '@home/components/attribute/add-attribute-dialog.component'; |
56 | import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; | 57 | import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; |
57 | -import { TIMEWINDOW_PANEL_DATA, TimewindowPanelComponent } from '@shared/components/time/timewindow-panel.component'; | ||
58 | import { | 58 | import { |
59 | EDIT_ATTRIBUTE_VALUE_PANEL_DATA, | 59 | EDIT_ATTRIBUTE_VALUE_PANEL_DATA, |
60 | EditAttributeValuePanelComponent, | 60 | EditAttributeValuePanelComponent, |
@@ -62,6 +62,24 @@ import { | @@ -62,6 +62,24 @@ import { | ||
62 | } from './edit-attribute-value-panel.component'; | 62 | } from './edit-attribute-value-panel.component'; |
63 | import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; | 63 | import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; |
64 | import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; | 64 | import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; |
65 | +import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; | ||
66 | +import { DataKey, Datasource, DatasourceType, Widget, widgetType } from '@shared/models/widget.models'; | ||
67 | +import { IAliasController, IStateController, StateParams } from '@core/api/widget-api.models'; | ||
68 | +import { AliasController, DummyAliasController } from '@core/api/alias-controller'; | ||
69 | +import { EntityAlias, EntityAliases } from '@shared/models/alias.models'; | ||
70 | +import { UtilsService } from '@core/services/utils.service'; | ||
71 | +import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; | ||
72 | +import { NULL_UUID } from '@shared/models/id/has-uuid'; | ||
73 | +import { WidgetService } from '@core/http/widget.service'; | ||
74 | +import { toWidgetInfo } from '../../models/widget-component.models'; | ||
75 | +import { EntityService } from '@core/http/entity.service'; | ||
76 | +import { SelectTargetLayoutDialogComponent } from '@home/pages/dashboard/layout/select-target-layout-dialog.component'; | ||
77 | +import { DashboardLayoutId } from '@shared/models/dashboard.models'; | ||
78 | +import { | ||
79 | + AddWidgetToDashboardDialogComponent, | ||
80 | + AddWidgetToDashboardDialogData | ||
81 | +} from '@home/components/attribute/add-widget-to-dashboard-dialog.component'; | ||
82 | +import { deepClone } from '@core/utils'; | ||
65 | 83 | ||
66 | 84 | ||
67 | @Component({ | 85 | @Component({ |
@@ -95,6 +113,15 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | @@ -95,6 +113,15 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | ||
95 | 113 | ||
96 | viewsInited = false; | 114 | viewsInited = false; |
97 | 115 | ||
116 | + selectedWidgetsBundleAlias: string = null; | ||
117 | + widgetsBundle: WidgetsBundle = null; | ||
118 | + widgetsLoaded = false; | ||
119 | + widgetsCarouselIndex = 0; | ||
120 | + widgetsList: Array<Array<Widget>> = []; | ||
121 | + widgetsListCache: Array<Array<Widget>> = []; | ||
122 | + aliasController: IAliasController; | ||
123 | + private widgetDatasource: Datasource; | ||
124 | + | ||
98 | private disableAttributeScopeSelectionValue: boolean; | 125 | private disableAttributeScopeSelectionValue: boolean; |
99 | get disableAttributeScopeSelection(): boolean { | 126 | get disableAttributeScopeSelection(): boolean { |
100 | return this.disableAttributeScopeSelectionValue; | 127 | return this.disableAttributeScopeSelectionValue; |
@@ -131,6 +158,9 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | @@ -131,6 +158,9 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | ||
131 | } | 158 | } |
132 | } | 159 | } |
133 | 160 | ||
161 | + @Input() | ||
162 | + entityName: string; | ||
163 | + | ||
134 | @ViewChild('searchInput', {static: false}) searchInputField: ElementRef; | 164 | @ViewChild('searchInput', {static: false}) searchInputField: ElementRef; |
135 | 165 | ||
136 | @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; | 166 | @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; |
@@ -143,12 +173,17 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | @@ -143,12 +173,17 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | ||
143 | public dialog: MatDialog, | 173 | public dialog: MatDialog, |
144 | private overlay: Overlay, | 174 | private overlay: Overlay, |
145 | private viewContainerRef: ViewContainerRef, | 175 | private viewContainerRef: ViewContainerRef, |
146 | - private dialogService: DialogService) { | 176 | + private dialogService: DialogService, |
177 | + private entityService: EntityService, | ||
178 | + private utils: UtilsService, | ||
179 | + private dashboardUtils: DashboardUtilsService, | ||
180 | + private widgetService: WidgetService, | ||
181 | + private zone: NgZone) { | ||
147 | super(store); | 182 | super(store); |
148 | this.dirtyValue = !this.activeValue; | 183 | this.dirtyValue = !this.activeValue; |
149 | const sortOrder: SortOrder = { property: 'key', direction: Direction.ASC }; | 184 | const sortOrder: SortOrder = { property: 'key', direction: Direction.ASC }; |
150 | this.pageLink = new PageLink(10, 0, null, sortOrder); | 185 | this.pageLink = new PageLink(10, 0, null, sortOrder); |
151 | - this.dataSource = new AttributeDatasource(this.attributeService, this.telemetryWsService, this.translate); | 186 | + this.dataSource = new AttributeDatasource(this.attributeService, this.telemetryWsService, this.zone, this.translate); |
152 | } | 187 | } |
153 | 188 | ||
154 | ngOnInit() { | 189 | ngOnInit() { |
@@ -329,15 +364,137 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | @@ -329,15 +364,137 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI | ||
329 | 364 | ||
330 | enterWidgetMode() { | 365 | enterWidgetMode() { |
331 | this.mode = 'widget'; | 366 | this.mode = 'widget'; |
367 | + this.widgetsList = []; | ||
368 | + this.widgetsListCache = []; | ||
369 | + this.widgetsLoaded = false; | ||
370 | + this.widgetsCarouselIndex = 0; | ||
371 | + this.widgetsBundle = null; | ||
372 | + this.selectedWidgetsBundleAlias = 'cards'; | ||
373 | + | ||
374 | + const entityAlias: EntityAlias = { | ||
375 | + id: this.utils.guid(), | ||
376 | + alias: this.entityName, | ||
377 | + filter: this.dashboardUtils.createSingleEntityFilter(this.entityIdValue) | ||
378 | + }; | ||
379 | + const entitiAliases: EntityAliases = {}; | ||
380 | + entitiAliases[entityAlias.id] = entityAlias; | ||
381 | + | ||
382 | + // @ts-ignore | ||
383 | + const stateController: IStateController = { | ||
384 | + getStateParams(): StateParams { | ||
385 | + return {}; | ||
386 | + } | ||
387 | + }; | ||
388 | + | ||
389 | + this.aliasController = new AliasController(this.utils, | ||
390 | + this.entityService, | ||
391 | + () => stateController, entitiAliases); | ||
392 | + | ||
393 | + const dataKeyType: DataKeyType = this.attributeScope === LatestTelemetry.LATEST_TELEMETRY ? | ||
394 | + DataKeyType.timeseries : DataKeyType.attribute; | ||
395 | + | ||
396 | + this.widgetDatasource = { | ||
397 | + type: DatasourceType.entity, | ||
398 | + entityAliasId: entityAlias.id, | ||
399 | + dataKeys: [] | ||
400 | + }; | ||
401 | + | ||
402 | + for (let i = 0; i < this.dataSource.selection.selected.length; i++) { | ||
403 | + const attribute = this.dataSource.selection.selected[i]; | ||
404 | + const dataKey: DataKey = { | ||
405 | + name: attribute.key, | ||
406 | + label: attribute.key, | ||
407 | + type: dataKeyType, | ||
408 | + color: this.utils.getMaterialColor(i), | ||
409 | + settings: {}, | ||
410 | + _hash: Math.random() | ||
411 | + }; | ||
412 | + this.widgetDatasource.dataKeys.push(dataKey); | ||
413 | + } | ||
414 | + } | ||
332 | 415 | ||
333 | - // TODO: | 416 | + onWidgetsCarouselIndexChanged() { |
417 | + if (this.mode === 'widget') { | ||
418 | + for (let i = 0; i < this.widgetsList.length; i++) { | ||
419 | + this.widgetsList[i].splice(0, this.widgetsList[i].length); | ||
420 | + if (i === this.widgetsCarouselIndex) { | ||
421 | + this.widgetsList[i].push(this.widgetsListCache[i][0]); | ||
422 | + } | ||
423 | + } | ||
424 | + } | ||
425 | + } | ||
426 | + | ||
427 | + onWidgetsBundleChanged() { | ||
428 | + if (this.mode === 'widget') { | ||
429 | + this.widgetsList = []; | ||
430 | + this.widgetsListCache = []; | ||
431 | + this.widgetsCarouselIndex = 0; | ||
432 | + if (this.widgetsBundle) { | ||
433 | + this.widgetsLoaded = false; | ||
434 | + const bundleAlias = this.widgetsBundle.alias; | ||
435 | + const isSystem = this.widgetsBundle.tenantId.id === NULL_UUID; | ||
436 | + this.widgetService.getBundleWidgetTypes(bundleAlias, isSystem).subscribe( | ||
437 | + (widgetTypes) => { | ||
438 | + widgetTypes = widgetTypes.sort((a, b) => { | ||
439 | + let result = widgetType[b.descriptor.type].localeCompare(widgetType[a.descriptor.type]); | ||
440 | + if (result === 0) { | ||
441 | + result = b.createdTime - a.createdTime; | ||
442 | + } | ||
443 | + return result; | ||
444 | + }); | ||
445 | + for (const type of widgetTypes) { | ||
446 | + const widgetInfo = toWidgetInfo(type); | ||
447 | + if (widgetInfo.type !== widgetType.static) { | ||
448 | + const sizeX = widgetInfo.sizeX * 2; | ||
449 | + const sizeY = widgetInfo.sizeY * 2; | ||
450 | + const col = Math.floor(Math.max(0, (20 - sizeX) / 2)); | ||
451 | + const widget: Widget = { | ||
452 | + isSystemType: isSystem, | ||
453 | + bundleAlias, | ||
454 | + typeAlias: widgetInfo.alias, | ||
455 | + type: widgetInfo.type, | ||
456 | + title: widgetInfo.widgetName, | ||
457 | + sizeX, | ||
458 | + sizeY, | ||
459 | + row: 0, | ||
460 | + col, | ||
461 | + config: JSON.parse(widgetInfo.defaultConfig) | ||
462 | + }; | ||
463 | + widget.config.title = widgetInfo.widgetName; | ||
464 | + widget.config.datasources = [this.widgetDatasource]; | ||
465 | + if ((this.attributeScope === LatestTelemetry.LATEST_TELEMETRY && widgetInfo.type !== widgetType.rpc) || | ||
466 | + widgetInfo.type === widgetType.latest) { | ||
467 | + const length = this.widgetsListCache.push([widget]); | ||
468 | + this.widgetsList.push(length === 1 ? [widget] : []); | ||
469 | + } | ||
470 | + } | ||
471 | + } | ||
472 | + this.widgetsLoaded = true; | ||
473 | + } | ||
474 | + ); | ||
475 | + } | ||
476 | + } | ||
477 | + } | ||
478 | + | ||
479 | + addWidgetToDashboard() { | ||
480 | + if (this.mode === 'widget' && this.widgetsListCache.length > 0) { | ||
481 | + const widget = this.widgetsListCache[this.widgetsCarouselIndex][0]; | ||
482 | + this.dialog.open<AddWidgetToDashboardDialogComponent, AddWidgetToDashboardDialogData> | ||
483 | + (AddWidgetToDashboardDialogComponent, { | ||
484 | + disableClose: true, | ||
485 | + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | ||
486 | + data: { | ||
487 | + entityId: this.entityIdValue, | ||
488 | + entityName: this.entityName, | ||
489 | + widget: deepClone(widget) | ||
490 | + } | ||
491 | + }).afterClosed(); | ||
492 | + } | ||
334 | } | 493 | } |
335 | 494 | ||
336 | exitWidgetMode() { | 495 | exitWidgetMode() { |
496 | + this.selectedWidgetsBundleAlias = null; | ||
337 | this.mode = 'default'; | 497 | this.mode = 'default'; |
338 | - // this.reloadAttributes(); | ||
339 | - | ||
340 | - // TODO: | ||
341 | } | 498 | } |
342 | 499 | ||
343 | } | 500 | } |
@@ -60,6 +60,9 @@ import { CustomDialogService } from './widget/dialog/custom-dialog.service'; | @@ -60,6 +60,9 @@ import { CustomDialogService } from './widget/dialog/custom-dialog.service'; | ||
60 | import { CustomDialogContainerComponent } from './widget/dialog/custom-dialog-container.component'; | 60 | import { CustomDialogContainerComponent } from './widget/dialog/custom-dialog-container.component'; |
61 | import { ImportExportService } from './import-export/import-export.service'; | 61 | import { ImportExportService } from './import-export/import-export.service'; |
62 | import { ImportDialogComponent } from './import-export/import-dialog.component'; | 62 | import { ImportDialogComponent } from './import-export/import-dialog.component'; |
63 | +import { AddWidgetToDashboardDialogComponent } from './attribute/add-widget-to-dashboard-dialog.component'; | ||
64 | +import { ImportDialogCsvComponent } from './import-export/import-dialog-csv.component'; | ||
65 | +import { TableColumnsAssignmentComponent } from './import-export/table-columns-assignment.component'; | ||
63 | 66 | ||
64 | @NgModule({ | 67 | @NgModule({ |
65 | entryComponents: [ | 68 | entryComponents: [ |
@@ -78,7 +81,9 @@ import { ImportDialogComponent } from './import-export/import-dialog.component'; | @@ -78,7 +81,9 @@ import { ImportDialogComponent } from './import-export/import-dialog.component'; | ||
78 | LegendConfigPanelComponent, | 81 | LegendConfigPanelComponent, |
79 | WidgetActionDialogComponent, | 82 | WidgetActionDialogComponent, |
80 | CustomDialogContainerComponent, | 83 | CustomDialogContainerComponent, |
81 | - ImportDialogComponent | 84 | + ImportDialogComponent, |
85 | + ImportDialogCsvComponent, | ||
86 | + AddWidgetToDashboardDialogComponent | ||
82 | ], | 87 | ], |
83 | declarations: | 88 | declarations: |
84 | [ | 89 | [ |
@@ -121,7 +126,10 @@ import { ImportDialogComponent } from './import-export/import-dialog.component'; | @@ -121,7 +126,10 @@ import { ImportDialogComponent } from './import-export/import-dialog.component'; | ||
121 | CustomActionPrettyResourcesTabsComponent, | 126 | CustomActionPrettyResourcesTabsComponent, |
122 | CustomActionPrettyEditorComponent, | 127 | CustomActionPrettyEditorComponent, |
123 | CustomDialogContainerComponent, | 128 | CustomDialogContainerComponent, |
124 | - ImportDialogComponent | 129 | + ImportDialogComponent, |
130 | + ImportDialogCsvComponent, | ||
131 | + AddWidgetToDashboardDialogComponent, | ||
132 | + TableColumnsAssignmentComponent | ||
125 | ], | 133 | ], |
126 | imports: [ | 134 | imports: [ |
127 | CommonModule, | 135 | CommonModule, |
@@ -159,7 +167,9 @@ import { ImportDialogComponent } from './import-export/import-dialog.component'; | @@ -159,7 +167,9 @@ import { ImportDialogComponent } from './import-export/import-dialog.component'; | ||
159 | CustomActionPrettyResourcesTabsComponent, | 167 | CustomActionPrettyResourcesTabsComponent, |
160 | CustomActionPrettyEditorComponent, | 168 | CustomActionPrettyEditorComponent, |
161 | CustomDialogContainerComponent, | 169 | CustomDialogContainerComponent, |
162 | - ImportDialogComponent | 170 | + ImportDialogComponent, |
171 | + ImportDialogCsvComponent, | ||
172 | + TableColumnsAssignmentComponent | ||
163 | ], | 173 | ], |
164 | providers: [ | 174 | providers: [ |
165 | WidgetComponentService, | 175 | WidgetComponentService, |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<form> | ||
19 | + <mat-toolbar fxLayout="row" color="primary"> | ||
20 | + <h2 translate>{{ importTitle }}</h2> | ||
21 | + <span fxFlex></span> | ||
22 | + <div [tb-help]="'entitiesImport'"></div> | ||
23 | + <button mat-button mat-icon-button | ||
24 | + (click)="cancel()" | ||
25 | + [disabled]="isImportData" | ||
26 | + type="button"> | ||
27 | + <mat-icon class="material-icons">close</mat-icon> | ||
28 | + </button> | ||
29 | + </mat-toolbar> | ||
30 | + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> | ||
31 | + </mat-progress-bar> | ||
32 | + <div mat-dialog-content> | ||
33 | + <mat-vertical-stepper [linear]="true" [selectedIndex]="selectedIndex" #importStepper> | ||
34 | + <mat-step [stepControl]="selectFileFormGroup"> | ||
35 | + <form [formGroup]="selectFileFormGroup"> | ||
36 | + <ng-template matStepLabel>{{ 'import.stepper-text.select-file' | translate }}</ng-template> | ||
37 | + <fieldset [disabled]="isLoading$ | async"> | ||
38 | + <tb-file-input formControlName="importData" | ||
39 | + required | ||
40 | + label="{{importFileLabel | translate}}" | ||
41 | + [allowedExtensions]="'csv'" | ||
42 | + [accept]="'.csv,application/csv,text/csv'" | ||
43 | + dropLabel="{{'import.drop-file-csv' | translate}}"> | ||
44 | + </tb-file-input> | ||
45 | + </fieldset> | ||
46 | + </form> | ||
47 | + <div fxLayout="row"> | ||
48 | + <span fxFlex></span> | ||
49 | + <button mat-button | ||
50 | + style="margin-right: 20px;" | ||
51 | + [disabled]="(isLoading$ | async)" | ||
52 | + (click)="cancel()">{{ 'action.cancel' | translate }}</button> | ||
53 | + <button mat-button mat-raised-button | ||
54 | + [disabled]="(isLoading$ | async) || selectFileFormGroup.invalid || !selectFileFormGroup.dirty" | ||
55 | + color="primary" | ||
56 | + (click)="nextStep(2)">{{ 'action.continue' | translate }}</button> | ||
57 | + </div> | ||
58 | + </mat-step> | ||
59 | + <mat-step [stepControl]="importParametersFormGroup"> | ||
60 | + <form [formGroup]="importParametersFormGroup"> | ||
61 | + <ng-template matStepLabel>{{ 'import.stepper-text.configuration' | translate }}</ng-template> | ||
62 | + <fieldset [disabled]="isLoading$ | async" fxLayout="column"> | ||
63 | + <mat-form-field class="mat-block"> | ||
64 | + <mat-label translate>import.csv-delimiter</mat-label> | ||
65 | + <mat-select required matInput formControlName="delim"> | ||
66 | + <mat-option *ngFor="let delimiter of delimiters" [value]="delimiter.key"> | ||
67 | + {{ delimiter.value }} | ||
68 | + </mat-option> | ||
69 | + </mat-select> | ||
70 | + </mat-form-field> | ||
71 | + <div fxLayout="column" fxLayoutGap="12px"> | ||
72 | + <mat-checkbox formControlName="isHeader"> | ||
73 | + {{ 'import.csv-first-line-header' | translate }} | ||
74 | + </mat-checkbox> | ||
75 | + <mat-checkbox formControlName="isUpdate"> | ||
76 | + {{ 'import.csv-update-data' | translate }} | ||
77 | + </mat-checkbox> | ||
78 | + </div> | ||
79 | + </fieldset> | ||
80 | + </form> | ||
81 | + <div fxLayout="row"> | ||
82 | + <button mat-button | ||
83 | + [disabled]="(isLoading$ | async)" | ||
84 | + (click)="previousStep()">{{ 'action.back' | translate }}</button> | ||
85 | + <span fxFlex></span> | ||
86 | + <button mat-button | ||
87 | + style="margin-right: 20px;" | ||
88 | + [disabled]="(isLoading$ | async)" | ||
89 | + (click)="cancel()">{{ 'action.cancel' | translate }}</button> | ||
90 | + <button mat-button mat-raised-button | ||
91 | + [disabled]="(isLoading$ | async)" | ||
92 | + color="primary" | ||
93 | + (click)="nextStep(3)">{{ 'action.continue' | translate }}</button> | ||
94 | + </div> | ||
95 | + </mat-step> | ||
96 | + <mat-step [stepControl]="columnTypesFormGroup"> | ||
97 | + <form [formGroup]="columnTypesFormGroup"> | ||
98 | + <ng-template matStepLabel>{{ 'import.stepper-text.column-type' | translate }}</ng-template> | ||
99 | + <tb-table-columns-assignment formControlName="columnsParam" [entityType]="entityType"></tb-table-columns-assignment> | ||
100 | + </form> | ||
101 | + <div fxLayout="row"> | ||
102 | + <button mat-button | ||
103 | + [disabled]="(isLoading$ | async)" | ||
104 | + (click)="previousStep()">{{ 'action.back' | translate }}</button> | ||
105 | + <span fxFlex></span> | ||
106 | + <button mat-button | ||
107 | + style="margin-right: 20px;" | ||
108 | + [disabled]="(isLoading$ | async)" | ||
109 | + (click)="cancel()">{{ 'action.cancel' | translate }}</button> | ||
110 | + <button mat-button mat-raised-button | ||
111 | + [disabled]="(isLoading$ | async) || columnTypesFormGroup.invalid || !columnTypesFormGroup.dirty" | ||
112 | + color="primary" | ||
113 | + (click)="nextStep(4)">{{ 'action.continue' | translate }}</button> | ||
114 | + </div> | ||
115 | + </mat-step> | ||
116 | + <mat-step> | ||
117 | + <ng-template matStepLabel>{{ 'import.stepper-text.creat-entities' | translate }}</ng-template> | ||
118 | + <mat-progress-bar color="warn" class="tb-import-progress" mode="determinate" [value]="progressCreate"> | ||
119 | + </mat-progress-bar> | ||
120 | + </mat-step> | ||
121 | + <mat-step> | ||
122 | + <ng-template matStepLabel>{{ 'import.stepper-text.done' | translate }}</ng-template> | ||
123 | + <div fxLayout="column"> | ||
124 | + <p class="mat-body-1" *ngIf="this.statistical?.create && this.statistical?.create.entity"> | ||
125 | + {{ translate.instant('import.message.create-entities', {count: this.statistical.create.entity}) }} | ||
126 | + </p> | ||
127 | + <p class="mat-body-1" *ngIf="this.statistical?.update && this.statistical?.update.entity"> | ||
128 | + {{ translate.instant('import.message.update-entities', {count: this.statistical.update.entity}) }} | ||
129 | + </p> | ||
130 | + <p class="mat-body-1" *ngIf="this.statistical?.error && this.statistical?.error.entity"> | ||
131 | + {{ translate.instant('import.message.error-entities', {count: this.statistical.error.entity}) }} | ||
132 | + </p> | ||
133 | + </div> | ||
134 | + <div fxLayout="row"> | ||
135 | + <span fxFlex></span> | ||
136 | + <button mat-button mat-raised-button | ||
137 | + [disabled]="(isLoading$ | async)" | ||
138 | + color="primary" | ||
139 | + (click)="nextStep(6)">{{ 'action.ok' | translate }}</button> | ||
140 | + </div> | ||
141 | + </mat-step> | ||
142 | + </mat-vertical-stepper> | ||
143 | + </div> | ||
144 | +</form> |
1 | +/** | ||
2 | + * Copyright © 2016-2019 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +:host ::ng-deep { | ||
17 | + .mat-dialog-content { | ||
18 | + .mat-vertical-content { | ||
19 | + form { | ||
20 | + overflow: hidden !important; | ||
21 | + padding-bottom: 12px; | ||
22 | + } | ||
23 | + } | ||
24 | + .mat-vertical-stepper-header { | ||
25 | + pointer-events: none !important; | ||
26 | + } | ||
27 | + .tb-import-progress{ | ||
28 | + margin: 7px 0; | ||
29 | + } | ||
30 | + } | ||
31 | +} |
1 | +/// | ||
2 | +/// Copyright © 2016-2019 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { Component, Inject, OnInit, ViewChild } from '@angular/core'; | ||
18 | +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; | ||
19 | +import { Store } from '@ngrx/store'; | ||
20 | +import { AppState } from '@core/core.state'; | ||
21 | +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; | ||
22 | +import { Router } from '@angular/router'; | ||
23 | +import { DialogComponent } from '@app/shared/components/dialog.component'; | ||
24 | +import { EntityType } from '@shared/models/entity-type.models'; | ||
25 | +import { TranslateService } from '@ngx-translate/core'; | ||
26 | +import { ActionNotificationShow } from '@core/notification/notification.actions'; | ||
27 | +import { MatVerticalStepper } from '@angular/material/stepper'; | ||
28 | +import { | ||
29 | + convertCSVToJson, | ||
30 | + CsvColumnParam, | ||
31 | + CsvToJsonConfig, | ||
32 | + CsvToJsonResult, | ||
33 | + ImportEntityColumnType | ||
34 | +} from '@home/components/import-export/import-export.models'; | ||
35 | +import { ImportEntitiesResultInfo, ImportEntityData } from '@app/shared/models/entity.models'; | ||
36 | +import { ImportExportService } from '@home/components/import-export/import-export.service'; | ||
37 | + | ||
38 | +export interface ImportDialogCsvData { | ||
39 | + entityType: EntityType; | ||
40 | + importTitle: string; | ||
41 | + importFileLabel: string; | ||
42 | +} | ||
43 | + | ||
44 | +@Component({ | ||
45 | + selector: 'tb-import-csv-dialog', | ||
46 | + templateUrl: './import-dialog-csv.component.html', | ||
47 | + providers: [], | ||
48 | + styleUrls: ['./import-dialog-csv.component.scss'] | ||
49 | +}) | ||
50 | +export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvComponent, boolean> | ||
51 | + implements OnInit { | ||
52 | + | ||
53 | + @ViewChild('importStepper', {static: true}) importStepper: MatVerticalStepper; | ||
54 | + | ||
55 | + entityType: EntityType; | ||
56 | + importTitle: string; | ||
57 | + importFileLabel: string; | ||
58 | + | ||
59 | + delimiters: {key: string, value: string}[] = [{ | ||
60 | + key: ',', | ||
61 | + value: ',' | ||
62 | + }, { | ||
63 | + key: ';', | ||
64 | + value: ';' | ||
65 | + }, { | ||
66 | + key: '|', | ||
67 | + value: '|' | ||
68 | + }, { | ||
69 | + key: '\t', | ||
70 | + value: 'Tab' | ||
71 | + }]; | ||
72 | + | ||
73 | + selectedIndex = 0; | ||
74 | + | ||
75 | + selectFileFormGroup: FormGroup; | ||
76 | + importParametersFormGroup: FormGroup; | ||
77 | + columnTypesFormGroup: FormGroup; | ||
78 | + | ||
79 | + isImportData = false; | ||
80 | + progressCreate = 0; | ||
81 | + statistical: ImportEntitiesResultInfo; | ||
82 | + | ||
83 | + private parseData: CsvToJsonResult; | ||
84 | + | ||
85 | + constructor(protected store: Store<AppState>, | ||
86 | + protected router: Router, | ||
87 | + @Inject(MAT_DIALOG_DATA) public data: ImportDialogCsvData, | ||
88 | + public dialogRef: MatDialogRef<ImportDialogCsvComponent, boolean>, | ||
89 | + public translate: TranslateService, | ||
90 | + private importExport: ImportExportService, | ||
91 | + private fb: FormBuilder) { | ||
92 | + super(store, router, dialogRef); | ||
93 | + this.entityType = data.entityType; | ||
94 | + this.importTitle = data.importTitle; | ||
95 | + this.importFileLabel = data.importFileLabel; | ||
96 | + | ||
97 | + this.selectFileFormGroup = this.fb.group( | ||
98 | + { | ||
99 | + importData: [null, [Validators.required]] | ||
100 | + } | ||
101 | + ); | ||
102 | + this.importParametersFormGroup = this.fb.group({ | ||
103 | + delim: [',', [Validators.required]], | ||
104 | + isHeader: [true, []], | ||
105 | + isUpdate: [true, []], | ||
106 | + }); | ||
107 | + this.columnTypesFormGroup = this.fb.group({ | ||
108 | + columnsParam: [[], []] | ||
109 | + }); | ||
110 | + } | ||
111 | + | ||
112 | + ngOnInit(): void { | ||
113 | + } | ||
114 | + | ||
115 | + cancel(): void { | ||
116 | + this.dialogRef.close(false); | ||
117 | + } | ||
118 | + | ||
119 | + previousStep() { | ||
120 | + this.importStepper.previous(); | ||
121 | + } | ||
122 | + | ||
123 | + nextStep(step: number) { | ||
124 | + switch (step) { | ||
125 | + case 2: | ||
126 | + this.importStepper.next(); | ||
127 | + break; | ||
128 | + case 3: | ||
129 | + const importData: string = this.selectFileFormGroup.get('importData').value; | ||
130 | + const parseData = this.parseCSV(importData); | ||
131 | + if (parseData === -1) { | ||
132 | + this.importStepper.previous(); | ||
133 | + this.importStepper.selected.reset(); | ||
134 | + } else { | ||
135 | + this.parseData = parseData as CsvToJsonResult; | ||
136 | + const columnsParam = this.createColumnsData(); | ||
137 | + this.columnTypesFormGroup.patchValue({columnsParam}, {emitEvent: true}); | ||
138 | + this.importStepper.next(); | ||
139 | + } | ||
140 | + break; | ||
141 | + case 4: | ||
142 | + this.importStepper.next(); | ||
143 | + this.isImportData = true; | ||
144 | + this.addEntities(); | ||
145 | + break; | ||
146 | + case 6: | ||
147 | + this.dialogRef.close(true); | ||
148 | + break; | ||
149 | + } | ||
150 | + } | ||
151 | + | ||
152 | + private parseCSV(importData: string): CsvToJsonResult | number { | ||
153 | + const config: CsvToJsonConfig = { | ||
154 | + delim: this.importParametersFormGroup.get('delim').value, | ||
155 | + header: this.importParametersFormGroup.get('isHeader').value | ||
156 | + }; | ||
157 | + return convertCSVToJson(importData, config, | ||
158 | + (messageId, params) => { | ||
159 | + this.store.dispatch(new ActionNotificationShow( | ||
160 | + {message: this.translate.instant(messageId, params), | ||
161 | + type: 'error'})); | ||
162 | + } | ||
163 | + ); | ||
164 | + } | ||
165 | + | ||
166 | + private createColumnsData(): CsvColumnParam[] { | ||
167 | + const columnsParam: CsvColumnParam[] = []; | ||
168 | + const isHeader: boolean = this.importParametersFormGroup.get('isHeader').value; | ||
169 | + for (let i = 0; i < this.parseData.headers.length; i++) { | ||
170 | + let columnParam: CsvColumnParam; | ||
171 | + if (isHeader && this.parseData.headers[i].search(/^(name|type)$/im) === 0) { | ||
172 | + columnParam = { | ||
173 | + type: ImportEntityColumnType[this.parseData.headers[i].toLowerCase()], | ||
174 | + key: this.parseData.headers[i].toLowerCase(), | ||
175 | + sampleData: this.parseData.rows[0][i] | ||
176 | + }; | ||
177 | + } else { | ||
178 | + columnParam = { | ||
179 | + type: ImportEntityColumnType.serverAttribute, | ||
180 | + key: isHeader ? this.parseData.headers[i] : '', | ||
181 | + sampleData: this.parseData.rows[0][i] | ||
182 | + }; | ||
183 | + } | ||
184 | + columnsParam.push(columnParam); | ||
185 | + } | ||
186 | + return columnsParam; | ||
187 | + } | ||
188 | + | ||
189 | + private addEntities() { | ||
190 | + const importData = this.parseData; | ||
191 | + const parameterColumns: CsvColumnParam[] = this.columnTypesFormGroup.get('columnsParam').value; | ||
192 | + const entitiesData: ImportEntityData[] = []; | ||
193 | + let sentDataLength = 0; | ||
194 | + for (let row = 0; row < importData.rows.length; row++) { | ||
195 | + const entityData: ImportEntityData = { | ||
196 | + name: '', | ||
197 | + type: '', | ||
198 | + accessToken: '', | ||
199 | + attributes: { | ||
200 | + server: [], | ||
201 | + shared: [] | ||
202 | + }, | ||
203 | + timeseries: [] | ||
204 | + }; | ||
205 | + const i = row; | ||
206 | + for (let j = 0; j < parameterColumns.length; j++) { | ||
207 | + switch (parameterColumns[j].type) { | ||
208 | + case ImportEntityColumnType.serverAttribute: | ||
209 | + entityData.attributes.server.push({ | ||
210 | + key: parameterColumns[j].key, | ||
211 | + value: importData.rows[i][j] | ||
212 | + }); | ||
213 | + break; | ||
214 | + case ImportEntityColumnType.timeseries: | ||
215 | + entityData.timeseries.push({ | ||
216 | + key: parameterColumns[j].key, | ||
217 | + value: importData.rows[i][j] | ||
218 | + }); | ||
219 | + break; | ||
220 | + case ImportEntityColumnType.sharedAttribute: | ||
221 | + entityData.attributes.shared.push({ | ||
222 | + key: parameterColumns[j].key, | ||
223 | + value: importData.rows[i][j] | ||
224 | + }); | ||
225 | + break; | ||
226 | + case ImportEntityColumnType.accessToken: | ||
227 | + entityData.accessToken = importData.rows[i][j]; | ||
228 | + break; | ||
229 | + case ImportEntityColumnType.name: | ||
230 | + entityData.name = importData.rows[i][j]; | ||
231 | + break; | ||
232 | + case ImportEntityColumnType.type: | ||
233 | + entityData.type = importData.rows[i][j]; | ||
234 | + break; | ||
235 | + } | ||
236 | + } | ||
237 | + entitiesData.push(entityData); | ||
238 | + } | ||
239 | + const createImportEntityCompleted = () => { | ||
240 | + sentDataLength++; | ||
241 | + this.progressCreate = Math.round((sentDataLength / importData.rows.length) * 100); | ||
242 | + }; | ||
243 | + | ||
244 | + const isUpdate: boolean = this.importParametersFormGroup.get('isUpdate').value; | ||
245 | + | ||
246 | + this.importExport.importEntities(entitiesData, this.entityType, isUpdate, | ||
247 | + createImportEntityCompleted, {ignoreErrors: true, resendRequest: true}).subscribe( | ||
248 | + (result) => { | ||
249 | + this.statistical = result; | ||
250 | + this.isImportData = false; | ||
251 | + this.importStepper.next(); | ||
252 | + } | ||
253 | + ); | ||
254 | + } | ||
255 | + | ||
256 | +} |
@@ -17,6 +17,8 @@ | @@ -17,6 +17,8 @@ | ||
17 | import { Widget, WidgetType } from '@app/shared/models/widget.models'; | 17 | import { Widget, WidgetType } from '@app/shared/models/widget.models'; |
18 | import { DashboardLayoutId } from '@shared/models/dashboard.models'; | 18 | import { DashboardLayoutId } from '@shared/models/dashboard.models'; |
19 | import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; | 19 | import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; |
20 | +import { ActionNotificationShow } from '@core/notification/notification.actions'; | ||
21 | +import { ActionType } from '@shared/models/audit-log.models'; | ||
20 | 22 | ||
21 | export interface ImportWidgetResult { | 23 | export interface ImportWidgetResult { |
22 | widget: Widget; | 24 | widget: Widget; |
@@ -27,3 +29,116 @@ export interface WidgetsBundleItem { | @@ -27,3 +29,116 @@ export interface WidgetsBundleItem { | ||
27 | widgetsBundle: WidgetsBundle; | 29 | widgetsBundle: WidgetsBundle; |
28 | widgetTypes: WidgetType[]; | 30 | widgetTypes: WidgetType[]; |
29 | } | 31 | } |
32 | + | ||
33 | +export interface CsvToJsonConfig { | ||
34 | + delim?: string; | ||
35 | + header?: boolean; | ||
36 | +} | ||
37 | + | ||
38 | +export interface CsvToJsonResult { | ||
39 | + headers?: string[]; | ||
40 | + rows?: any[][]; | ||
41 | +} | ||
42 | + | ||
43 | +export enum ImportEntityColumnType { | ||
44 | + name = 'NAME', | ||
45 | + type = 'TYPE', | ||
46 | + clientAttribute = 'CLIENT_ATTRIBUTE', | ||
47 | + sharedAttribute = 'SHARED_ATTRIBUTE', | ||
48 | + serverAttribute = 'SERVER_ATTRIBUTE', | ||
49 | + timeseries = 'TIMESERIES', | ||
50 | + entityField = 'ENTITY_FIELD', | ||
51 | + accessToken = 'ACCESS_TOKEN' | ||
52 | +} | ||
53 | + | ||
54 | +export const importEntityObjectColumns = | ||
55 | + [ImportEntityColumnType.name, ImportEntityColumnType.type, ImportEntityColumnType.accessToken]; | ||
56 | + | ||
57 | +export const importEntityColumnTypeTranslations = new Map<ImportEntityColumnType, string>( | ||
58 | + [ | ||
59 | + [ImportEntityColumnType.name, 'import.column-type.name'], | ||
60 | + [ImportEntityColumnType.type, 'import.column-type.type'], | ||
61 | + [ImportEntityColumnType.clientAttribute, 'import.column-type.client-attribute'], | ||
62 | + [ImportEntityColumnType.sharedAttribute, 'import.column-type.shared-attribute'], | ||
63 | + [ImportEntityColumnType.serverAttribute, 'import.column-type.server-attribute'], | ||
64 | + [ImportEntityColumnType.timeseries, 'import.column-type.timeseries'], | ||
65 | + [ImportEntityColumnType.entityField, 'import.column-type.entity-field'], | ||
66 | + [ImportEntityColumnType.accessToken, 'import.column-type.access-token'], | ||
67 | + ] | ||
68 | +); | ||
69 | + | ||
70 | +export interface CsvColumnParam { | ||
71 | + type: ImportEntityColumnType; | ||
72 | + key: string; | ||
73 | + sampleData: any; | ||
74 | +} | ||
75 | + | ||
76 | +export function convertCSVToJson(csvdata: string, config: CsvToJsonConfig, | ||
77 | + onError: (messageId: string, params?: any) => void): CsvToJsonResult | number { | ||
78 | + config = config || {}; | ||
79 | + const delim = config.delim || ','; | ||
80 | + const header = config.header || false; | ||
81 | + const result: CsvToJsonResult = {}; | ||
82 | + const csvlines = csvdata.split(/[\r\n]+/); | ||
83 | + const csvheaders = splitCSV(csvlines[0], delim); | ||
84 | + if (csvheaders.length < 2) { | ||
85 | + onError('import.import-csv-number-columns-error'); | ||
86 | + return -1; | ||
87 | + } | ||
88 | + const csvrows = header ? csvlines.slice(1, csvlines.length) : csvlines; | ||
89 | + result.headers = csvheaders; | ||
90 | + result.rows = []; | ||
91 | + for (const row of csvrows) { | ||
92 | + if (row.length === 0) { | ||
93 | + break; | ||
94 | + } | ||
95 | + const rowitems: any[] = splitCSV(row, delim); | ||
96 | + if (rowitems.length !== result.headers.length) { | ||
97 | + onError('import.import-csv-invalid-format-error', {line: (header ? result.rows.length + 2 : result.rows.length + 1)}); | ||
98 | + return -1; | ||
99 | + } | ||
100 | + for (let i = 0; i < rowitems.length; i++) { | ||
101 | + rowitems[i] = convertStringToJSType(rowitems[i]); | ||
102 | + } | ||
103 | + result.rows.push(rowitems); | ||
104 | + } | ||
105 | + return result; | ||
106 | +} | ||
107 | + | ||
108 | +function splitCSV(str: string, sep: string): string[] { | ||
109 | + let foo: string[]; | ||
110 | + let x: number; | ||
111 | + let tl: string; | ||
112 | + for (foo = str.split(sep = sep || ','), x = foo.length - 1, tl; x >= 0; x--) { | ||
113 | + if (foo[x].replace(/"\s+$/, '"').charAt(foo[x].length - 1) === '"') { | ||
114 | + if ((tl = foo[x].replace(/^\s+"/, '"')).length > 1 && tl.charAt(0) === '"') { | ||
115 | + foo[x] = foo[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"'); | ||
116 | + } else if (x) { | ||
117 | + foo.splice(x - 1, 2, [foo[x - 1], foo[x]].join(sep)); | ||
118 | + } else { | ||
119 | + foo = foo.shift().split(sep).concat(foo); | ||
120 | + } | ||
121 | + } else { | ||
122 | + foo[x].replace(/""/g, '"'); | ||
123 | + } | ||
124 | + } | ||
125 | + return foo; | ||
126 | +} | ||
127 | + | ||
128 | +function isNumeric(str: any): boolean { | ||
129 | + str = str.replace(',', '.'); | ||
130 | + return !isNaN(parseFloat(str)) && isFinite(str); | ||
131 | +} | ||
132 | + | ||
133 | +function convertStringToJSType(str: string): any { | ||
134 | + if (isNumeric(str.replace(',', '.'))) { | ||
135 | + return parseFloat(str.replace(',', '.')); | ||
136 | + } | ||
137 | + if (str.search(/^(true|false)$/im) === 0) { | ||
138 | + return str === 'true'; | ||
139 | + } | ||
140 | + if (str === '') { | ||
141 | + return null; | ||
142 | + } | ||
143 | + return str; | ||
144 | +} |
@@ -35,7 +35,7 @@ import { | @@ -35,7 +35,7 @@ import { | ||
35 | import { MatDialog } from '@angular/material/dialog'; | 35 | import { MatDialog } from '@angular/material/dialog'; |
36 | import { ImportDialogComponent, ImportDialogData } from '@home/components/import-export/import-dialog.component'; | 36 | import { ImportDialogComponent, ImportDialogData } from '@home/components/import-export/import-dialog.component'; |
37 | import { forkJoin, Observable, of } from 'rxjs'; | 37 | import { forkJoin, Observable, of } from 'rxjs'; |
38 | -import { catchError, map, mergeMap } from 'rxjs/operators'; | 38 | +import { catchError, map, mergeMap, tap } from 'rxjs/operators'; |
39 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; | 39 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
40 | import { EntityService } from '@core/http/entity.service'; | 40 | import { EntityService } from '@core/http/entity.service'; |
41 | import { Widget, WidgetSize, WidgetType } from '@shared/models/widget.models'; | 41 | import { Widget, WidgetSize, WidgetType } from '@shared/models/widget.models'; |
@@ -44,12 +44,15 @@ import { | @@ -44,12 +44,15 @@ import { | ||
44 | EntityAliasesDialogData | 44 | EntityAliasesDialogData |
45 | } from '@home/components/alias/entity-aliases-dialog.component'; | 45 | } from '@home/components/alias/entity-aliases-dialog.component'; |
46 | import { ItemBufferService, WidgetItem } from '@core/services/item-buffer.service'; | 46 | import { ItemBufferService, WidgetItem } from '@core/services/item-buffer.service'; |
47 | -import { ImportWidgetResult, WidgetsBundleItem } from './import-export.models'; | 47 | +import { CsvToJsonConfig, ImportWidgetResult, WidgetsBundleItem, CsvToJsonResult } from './import-export.models'; |
48 | import { EntityType } from '@shared/models/entity-type.models'; | 48 | import { EntityType } from '@shared/models/entity-type.models'; |
49 | import { UtilsService } from '@core/services/utils.service'; | 49 | import { UtilsService } from '@core/services/utils.service'; |
50 | import { WidgetService } from '@core/http/widget.service'; | 50 | import { WidgetService } from '@core/http/widget.service'; |
51 | import { NULL_UUID } from '@shared/models/id/has-uuid'; | 51 | import { NULL_UUID } from '@shared/models/id/has-uuid'; |
52 | import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; | 52 | import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; |
53 | +import { ImportDialogCsvComponent, ImportDialogCsvData } from './import-dialog-csv.component'; | ||
54 | +import { ImportEntityData, ImportEntitiesResultInfo } from '@shared/models/entity.models'; | ||
55 | +import { RequestConfig } from '@core/http/http-utils'; | ||
53 | 56 | ||
54 | @Injectable() | 57 | @Injectable() |
55 | export class ImportExportService { | 58 | export class ImportExportService { |
@@ -324,6 +327,55 @@ export class ImportExportService { | @@ -324,6 +327,55 @@ export class ImportExportService { | ||
324 | ); | 327 | ); |
325 | } | 328 | } |
326 | 329 | ||
330 | + public importEntities(entitiesData: ImportEntityData[], entityType: EntityType, updateData: boolean, | ||
331 | + importEntityCompleted?: () => void, config?: RequestConfig): Observable<ImportEntitiesResultInfo> { | ||
332 | + let partSize = 100; | ||
333 | + partSize = entitiesData.length > partSize ? partSize : entitiesData.length; | ||
334 | + | ||
335 | + let statisticalInfo: ImportEntitiesResultInfo = {}; | ||
336 | + const importEntitiesObservables: Observable<ImportEntitiesResultInfo>[] = []; | ||
337 | + for (let i = 0; i < partSize; i++) { | ||
338 | + const importEntityPromise = | ||
339 | + this.entityService.saveEntityParameters(entityType, entitiesData[i], updateData, config).pipe( | ||
340 | + tap((res) => { | ||
341 | + if (importEntityCompleted) { | ||
342 | + importEntityCompleted(); | ||
343 | + } | ||
344 | + }) | ||
345 | + ); | ||
346 | + importEntitiesObservables.push(importEntityPromise); | ||
347 | + } | ||
348 | + return forkJoin(importEntitiesObservables).pipe( | ||
349 | + mergeMap((responses) => { | ||
350 | + for (const response of responses) { | ||
351 | + statisticalInfo = this.sumObject(statisticalInfo, response); | ||
352 | + } | ||
353 | + entitiesData.splice(0, partSize); | ||
354 | + if (entitiesData.length) { | ||
355 | + return this.importEntities(entitiesData, entityType, updateData, importEntityCompleted, config).pipe( | ||
356 | + map((response) => { | ||
357 | + return this.sumObject(statisticalInfo, response) as ImportEntitiesResultInfo; | ||
358 | + }) | ||
359 | + ); | ||
360 | + } else { | ||
361 | + return of(statisticalInfo); | ||
362 | + } | ||
363 | + }) | ||
364 | + ); | ||
365 | + } | ||
366 | + | ||
367 | + private sumObject(obj1: any, obj2: any): any { | ||
368 | + Object.keys(obj2).map((key) => { | ||
369 | + if (isObject(obj2[key])) { | ||
370 | + obj1[key] = obj1[key] || {}; | ||
371 | + obj1[key] = {...obj1[key], ...this.sumObject(obj1[key], obj2[key])}; | ||
372 | + } else { | ||
373 | + obj1[key] = (obj1[key] || 0) + obj2[key]; | ||
374 | + } | ||
375 | + }); | ||
376 | + return obj1; | ||
377 | + } | ||
378 | + | ||
327 | private handleExportError(e: any, errorDetailsMessageId: string) { | 379 | private handleExportError(e: any, errorDetailsMessageId: string) { |
328 | let message = e; | 380 | let message = e; |
329 | if (!message) { | 381 | if (!message) { |
ui-ngx/src/app/modules/home/components/import-export/table-columns-assignment.component.html
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<mat-table [dataSource]="dataSource"> | ||
19 | + <ng-container matColumnDef="order"> | ||
20 | + <mat-header-cell *matHeaderCellDef></mat-header-cell> | ||
21 | + <mat-cell *matCellDef="let column; let i = index"> | ||
22 | + {{ (i+1) }} | ||
23 | + </mat-cell> | ||
24 | + </ng-container> | ||
25 | + <ng-container matColumnDef="sampleData"> | ||
26 | + <mat-header-cell *matHeaderCellDef> {{ 'import.column-example' | translate }} </mat-header-cell> | ||
27 | + <mat-cell *matCellDef="let column"> | ||
28 | + {{column.sampleData}} | ||
29 | + </mat-cell> | ||
30 | + </ng-container> | ||
31 | + <ng-container matColumnDef="type"> | ||
32 | + <mat-header-cell *matHeaderCellDef> {{ 'import.column-type.column-type' | translate }} </mat-header-cell> | ||
33 | + <mat-cell *matCellDef="let column"> | ||
34 | + <mat-select matInput [(ngModel)]="column.type" (ngModelChange)="columnsUpdated()"> | ||
35 | + <mat-option *ngFor="let type of columnTypes" [value]="type.value" [disabled]="type.disabled"> | ||
36 | + {{ columnTypesTranslations.get(type.value) | translate }} | ||
37 | + </mat-option> | ||
38 | + </mat-select> | ||
39 | + </mat-cell> | ||
40 | + </ng-container> | ||
41 | + <ng-container matColumnDef="key"> | ||
42 | + <mat-header-cell *matHeaderCellDef> {{ 'import.column-key' | translate }} </mat-header-cell> | ||
43 | + <mat-cell *matCellDef="let column"> | ||
44 | + <mat-form-field floatLabel="always" hideRequiredMarker | ||
45 | + *ngIf="column.type !== importEntityColumnType.name && | ||
46 | + column.type !== importEntityColumnType.type && | ||
47 | + column.type !== importEntityColumnType.accessToken"> | ||
48 | + <mat-label></mat-label> | ||
49 | + <input matInput required | ||
50 | + [(ngModel)]="column.key" (ngModelChange)="columnsUpdated()" | ||
51 | + placeholder="{{ 'import.column-value' | translate }}"/> | ||
52 | + </mat-form-field> | ||
53 | + </mat-cell> | ||
54 | + </ng-container> | ||
55 | + <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> | ||
56 | + <mat-row *matRowDef="let column; columns: displayedColumns;"></mat-row> | ||
57 | +</mat-table> | ||
58 | +<mat-divider></mat-divider> |
ui-ngx/src/app/modules/home/components/import-export/table-columns-assignment.component.scss
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2019 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +:host { | ||
17 | + .mat-column-order { | ||
18 | + flex: 0 0 40px; | ||
19 | + } | ||
20 | + .mat-column-sampleData { | ||
21 | + flex: 0 0 120px; | ||
22 | + } | ||
23 | + .mat-column-type { | ||
24 | + flex: 0 0 120px; | ||
25 | + } | ||
26 | +} |
ui-ngx/src/app/modules/home/components/import-export/table-columns-assignment.component.ts
0 → 100644
1 | +/// | ||
2 | +/// Copyright © 2016-2019 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { Component, ElementRef, forwardRef, Input, OnInit } from '@angular/core'; | ||
18 | +import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; | ||
19 | +import { Store } from '@ngrx/store'; | ||
20 | +import { AppState } from '@core/core.state'; | ||
21 | +import { EntityType } from '@shared/models/entity-type.models'; | ||
22 | +import { CsvColumnParam, ImportEntityColumnType, importEntityColumnTypeTranslations, | ||
23 | + importEntityObjectColumns } from '@home/components/import-export/import-export.models'; | ||
24 | +import { CollectionViewer, DataSource } from '@angular/cdk/typings/collections'; | ||
25 | +import { BehaviorSubject, Observable } from 'rxjs'; | ||
26 | + | ||
27 | +@Component({ | ||
28 | + selector: 'tb-table-columns-assignment', | ||
29 | + templateUrl: './table-columns-assignment.component.html', | ||
30 | + styleUrls: ['./table-columns-assignment.component.scss'], | ||
31 | + providers: [ | ||
32 | + { | ||
33 | + provide: NG_VALUE_ACCESSOR, | ||
34 | + useExisting: forwardRef(() => TableColumnsAssignmentComponent), | ||
35 | + multi: true | ||
36 | + }, | ||
37 | + { | ||
38 | + provide: NG_VALIDATORS, | ||
39 | + useExisting: forwardRef(() => TableColumnsAssignmentComponent), | ||
40 | + multi: true, | ||
41 | + } | ||
42 | + ] | ||
43 | +}) | ||
44 | +export class TableColumnsAssignmentComponent implements OnInit, ControlValueAccessor, Validator { | ||
45 | + | ||
46 | + @Input() entityType: EntityType; | ||
47 | + | ||
48 | + @Input() disabled: boolean; | ||
49 | + | ||
50 | + dataSource = new CsvColumnsDatasource(); | ||
51 | + | ||
52 | + displayedColumns = ['order', 'sampleData', 'type', 'key']; | ||
53 | + | ||
54 | + importEntityColumnType = ImportEntityColumnType; | ||
55 | + | ||
56 | + columnTypes: AssignmentColumnType[] = []; | ||
57 | + | ||
58 | + columnTypesTranslations = importEntityColumnTypeTranslations; | ||
59 | + | ||
60 | + private columns: CsvColumnParam[]; | ||
61 | + | ||
62 | + private valid = true; | ||
63 | + | ||
64 | + private propagateChangePending = false; | ||
65 | + private propagateChange = null; | ||
66 | + | ||
67 | + constructor(public elementRef: ElementRef, | ||
68 | + protected store: Store<AppState>) { | ||
69 | + } | ||
70 | + | ||
71 | + ngOnInit(): void { | ||
72 | + this.columnTypes.push( | ||
73 | + { value: ImportEntityColumnType.name }, | ||
74 | + { value: ImportEntityColumnType.type }, | ||
75 | + ); | ||
76 | + switch (this.entityType) { | ||
77 | + case EntityType.DEVICE: | ||
78 | + this.columnTypes.push( | ||
79 | + { value: ImportEntityColumnType.sharedAttribute }, | ||
80 | + { value: ImportEntityColumnType.serverAttribute }, | ||
81 | + { value: ImportEntityColumnType.timeseries }, | ||
82 | + { value: ImportEntityColumnType.accessToken } | ||
83 | + ); | ||
84 | + break; | ||
85 | + case EntityType.ASSET: | ||
86 | + this.columnTypes.push( | ||
87 | + { value: ImportEntityColumnType.serverAttribute }, | ||
88 | + { value: ImportEntityColumnType.timeseries } | ||
89 | + ); | ||
90 | + break; | ||
91 | + } | ||
92 | + } | ||
93 | + | ||
94 | + registerOnChange(fn: any): void { | ||
95 | + this.propagateChange = fn; | ||
96 | + if (this.propagateChangePending) { | ||
97 | + this.propagateChange(this.columns); | ||
98 | + this.propagateChangePending = false; | ||
99 | + } | ||
100 | + } | ||
101 | + | ||
102 | + registerOnTouched(fn: any): void { | ||
103 | + } | ||
104 | + | ||
105 | + setDisabledState(isDisabled: boolean): void { | ||
106 | + this.disabled = isDisabled; | ||
107 | + } | ||
108 | + | ||
109 | + columnsUpdated() { | ||
110 | + const isSelectName = this.columns.findIndex((column) => column.type === ImportEntityColumnType.name) > -1; | ||
111 | + const isSelectType = this.columns.findIndex((column) => column.type === ImportEntityColumnType.type) > -1; | ||
112 | + const isSelectCredentials = this.columns.findIndex((column) => column.type === ImportEntityColumnType.accessToken) > -1; | ||
113 | + const hasInvalidColumn = this.columns.findIndex((column) => !this.columnValid(column)) > -1; | ||
114 | + | ||
115 | + this.valid = isSelectName && isSelectType && !hasInvalidColumn; | ||
116 | + | ||
117 | + this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.name).disabled = isSelectName; | ||
118 | + this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.type).disabled = isSelectType; | ||
119 | + const accessTokenColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.accessToken); | ||
120 | + if (accessTokenColumnType) { | ||
121 | + accessTokenColumnType.disabled = isSelectCredentials; | ||
122 | + } | ||
123 | + if (this.propagateChange) { | ||
124 | + this.propagateChange(this.columns); | ||
125 | + } else { | ||
126 | + this.propagateChangePending = true; | ||
127 | + } | ||
128 | + } | ||
129 | + | ||
130 | + private columnValid(column: CsvColumnParam): boolean { | ||
131 | + if (!importEntityObjectColumns.includes(column.type)) { | ||
132 | + return column.key && column.key.trim().length > 0; | ||
133 | + } else { | ||
134 | + return true; | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + public validate(c: FormControl) { | ||
139 | + return (this.valid) ? null : { | ||
140 | + columnsInvalid: true | ||
141 | + }; | ||
142 | + return null; | ||
143 | + } | ||
144 | + | ||
145 | + writeValue(value: CsvColumnParam[]): void { | ||
146 | + this.columns = value; | ||
147 | + this.dataSource.setColumns(this.columns); | ||
148 | + this.columnsUpdated(); | ||
149 | + } | ||
150 | +} | ||
151 | + | ||
152 | +interface AssignmentColumnType { | ||
153 | + value: ImportEntityColumnType; | ||
154 | + disabled?: boolean; | ||
155 | +} | ||
156 | + | ||
157 | +class CsvColumnsDatasource implements DataSource<CsvColumnParam> { | ||
158 | + | ||
159 | + private columnsSubject = new BehaviorSubject<CsvColumnParam[]>([]); | ||
160 | + | ||
161 | + constructor() {} | ||
162 | + | ||
163 | + connect(collectionViewer: CollectionViewer): Observable<CsvColumnParam[] | ReadonlyArray<CsvColumnParam>> { | ||
164 | + return this.columnsSubject.asObservable(); | ||
165 | + } | ||
166 | + | ||
167 | + disconnect(collectionViewer: CollectionViewer): void { | ||
168 | + this.columnsSubject.complete(); | ||
169 | + } | ||
170 | + | ||
171 | + setColumns(columns: CsvColumnParam[]) { | ||
172 | + this.columnsSubject.next(columns); | ||
173 | + } | ||
174 | + | ||
175 | +} |
@@ -162,7 +162,7 @@ export class WidgetComponentService { | @@ -162,7 +162,7 @@ export class WidgetComponentService { | ||
162 | } else { | 162 | } else { |
163 | fetchQueue = new Array<Subject<WidgetInfo>>(); | 163 | fetchQueue = new Array<Subject<WidgetInfo>>(); |
164 | this.widgetsInfoFetchQueue.set(key, fetchQueue); | 164 | this.widgetsInfoFetchQueue.set(key, fetchQueue); |
165 | - this.widgetService.getWidgetType(bundleAlias, widgetTypeAlias, isSystem, true, false).subscribe( | 165 | + this.widgetService.getWidgetType(bundleAlias, widgetTypeAlias, isSystem, {ignoreErrors: true}).subscribe( |
166 | (widgetType) => { | 166 | (widgetType) => { |
167 | this.loadWidget(widgetType, bundleAlias, isSystem, widgetInfoSubject); | 167 | this.loadWidget(widgetType, bundleAlias, isSystem, widgetInfoSubject); |
168 | }, | 168 | }, |
@@ -705,8 +705,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | @@ -705,8 +705,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | ||
705 | {entityType: entity.entityType, id: entity.id}, | 705 | {entityType: entity.entityType, id: entity.id}, |
706 | query, | 706 | query, |
707 | dataKeyType, | 707 | dataKeyType, |
708 | - true, | ||
709 | - true | 708 | + {ignoreLoading: true, ignoreErrors: true} |
710 | ).pipe( | 709 | ).pipe( |
711 | map((keys) => { | 710 | map((keys) => { |
712 | const dataKeys: Array<DataKey> = []; | 711 | const dataKeys: Array<DataKey> = []; |
@@ -19,6 +19,7 @@ import { CommonModule } from '@angular/common'; | @@ -19,6 +19,7 @@ import { CommonModule } from '@angular/common'; | ||
19 | import { SharedModule } from '@app/shared/shared.module'; | 19 | import { SharedModule } from '@app/shared/shared.module'; |
20 | import {AssignToCustomerDialogComponent} from '@modules/home/dialogs/assign-to-customer-dialog.component'; | 20 | import {AssignToCustomerDialogComponent} from '@modules/home/dialogs/assign-to-customer-dialog.component'; |
21 | import {AddEntitiesToCustomerDialogComponent} from '@modules/home/dialogs/add-entities-to-customer-dialog.component'; | 21 | import {AddEntitiesToCustomerDialogComponent} from '@modules/home/dialogs/add-entities-to-customer-dialog.component'; |
22 | +import { HomeDialogsService } from './home-dialogs.service'; | ||
22 | 23 | ||
23 | @NgModule({ | 24 | @NgModule({ |
24 | entryComponents: [ | 25 | entryComponents: [ |
@@ -37,6 +38,9 @@ import {AddEntitiesToCustomerDialogComponent} from '@modules/home/dialogs/add-en | @@ -37,6 +38,9 @@ import {AddEntitiesToCustomerDialogComponent} from '@modules/home/dialogs/add-en | ||
37 | exports: [ | 38 | exports: [ |
38 | AssignToCustomerDialogComponent, | 39 | AssignToCustomerDialogComponent, |
39 | AddEntitiesToCustomerDialogComponent | 40 | AddEntitiesToCustomerDialogComponent |
41 | + ], | ||
42 | + providers: [ | ||
43 | + HomeDialogsService | ||
40 | ] | 44 | ] |
41 | }) | 45 | }) |
42 | export class HomeDialogsModule { } | 46 | export class HomeDialogsModule { } |
1 | +/// | ||
2 | +/// Copyright © 2016-2019 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { Injectable } from '@angular/core'; | ||
18 | +import { TranslateService } from '@ngx-translate/core'; | ||
19 | +import { AuthService } from '@core/auth/auth.service'; | ||
20 | +import { MatDialog } from '@angular/material/dialog'; | ||
21 | +import { EntityType } from '@shared/models/entity-type.models'; | ||
22 | +import { Observable } from 'rxjs'; | ||
23 | +import { | ||
24 | + ImportDialogCsvComponent, | ||
25 | + ImportDialogCsvData | ||
26 | +} from '@home/components/import-export/import-dialog-csv.component'; | ||
27 | + | ||
28 | +@Injectable() | ||
29 | +export class HomeDialogsService { | ||
30 | + constructor( | ||
31 | + private dialog: MatDialog | ||
32 | + ) { | ||
33 | + } | ||
34 | + | ||
35 | + public importEntities(entityType: EntityType): Observable<boolean> { | ||
36 | + switch (entityType) { | ||
37 | + case EntityType.DEVICE: | ||
38 | + return this.openImportDialogCSV(entityType, 'device.import', 'device.device-file'); | ||
39 | + case EntityType.ASSET: | ||
40 | + return this.openImportDialogCSV(entityType, 'asset.import', 'asset.asset-file'); | ||
41 | + break; | ||
42 | + } | ||
43 | + } | ||
44 | + | ||
45 | + private openImportDialogCSV(entityType: EntityType, importTitle: string, importFileLabel: string): Observable<boolean> { | ||
46 | + return this.dialog.open<ImportDialogCsvComponent, ImportDialogCsvData, | ||
47 | + any>(ImportDialogCsvComponent, { | ||
48 | + disableClose: true, | ||
49 | + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | ||
50 | + data: { | ||
51 | + entityType, | ||
52 | + importTitle, | ||
53 | + importFileLabel | ||
54 | + } | ||
55 | + }).afterClosed(); | ||
56 | + } | ||
57 | +} |
@@ -19,7 +19,7 @@ | @@ -19,7 +19,7 @@ | ||
19 | <mat-sidenav #sidenav class="tb-site-sidenav mat-elevation-z2" | 19 | <mat-sidenav #sidenav class="tb-site-sidenav mat-elevation-z2" |
20 | (click)="sidenavClicked()" | 20 | (click)="sidenavClicked()" |
21 | [mode]="sidenavMode" | 21 | [mode]="sidenavMode" |
22 | - [opened]="sidenavOpened"> | 22 | + [opened]="sidenavOpened && !forceFullscreen"> |
23 | <header class="tb-nav-header"> | 23 | <header class="tb-nav-header"> |
24 | <mat-toolbar color="primary" class="tb-nav-header-toolbar"> | 24 | <mat-toolbar color="primary" class="tb-nav-header-toolbar"> |
25 | <div fxFlex="auto" fxLayout="row"> | 25 | <div fxFlex="auto" fxLayout="row"> |
@@ -35,9 +35,12 @@ | @@ -35,9 +35,12 @@ | ||
35 | <mat-sidenav-content> | 35 | <mat-sidenav-content> |
36 | <div fxLayout="column" role="main" style="height: 100%;"> | 36 | <div fxLayout="column" role="main" style="height: 100%;"> |
37 | <mat-toolbar fxLayout="row" color="primary" class="mat-elevation-z1 tb-primary-toolbar"> | 37 | <mat-toolbar fxLayout="row" color="primary" class="mat-elevation-z1 tb-primary-toolbar"> |
38 | - <button mat-button mat-icon-button id="main" fxHide.gt-sm (click)="sidenav.toggle()"> | 38 | + <button [fxShow]="!forceFullscreen" mat-button mat-icon-button id="main" fxHide.gt-sm (click)="sidenav.toggle()"> |
39 | <mat-icon class="material-icons">menu</mat-icon> | 39 | <mat-icon class="material-icons">menu</mat-icon> |
40 | </button> | 40 | </button> |
41 | + <button [fxShow]="forceFullscreen" mat-button mat-icon-button (click)="goBack()"> | ||
42 | + <mat-icon class="material-icons">arrow_back</mat-icon> | ||
43 | + </button> | ||
41 | <div fxFlex tb-breadcrumb [activeComponent]="activeComponent" class="mat-toolbar-tools"> | 44 | <div fxFlex tb-breadcrumb [activeComponent]="activeComponent" class="mat-toolbar-tools"> |
42 | </div> | 45 | </div> |
43 | <button *ngIf="fullscreenEnabled" mat-button mat-icon-button fxHide.xs fxHide.sm (click)="toggleFullscreen()"> | 46 | <button *ngIf="fullscreenEnabled" mat-button mat-icon-button fxHide.xs fxHide.sm (click)="toggleFullscreen()"> |
@@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Component, OnInit, ViewChild } from '@angular/core'; | 17 | +import { Component, Inject, OnInit, ViewChild } from '@angular/core'; |
18 | import { Observable } from 'rxjs'; | 18 | import { Observable } from 'rxjs'; |
19 | import { select, Store } from '@ngrx/store'; | 19 | import { select, Store } from '@ngrx/store'; |
20 | import { map, mergeMap, take } from 'rxjs/operators'; | 20 | import { map, mergeMap, take } from 'rxjs/operators'; |
@@ -26,12 +26,14 @@ import { AppState } from '@core/core.state'; | @@ -26,12 +26,14 @@ import { AppState } from '@core/core.state'; | ||
26 | import { AuthService } from '@core/auth/auth.service'; | 26 | import { AuthService } from '@core/auth/auth.service'; |
27 | import { UserService } from '@core/http/user.service'; | 27 | import { UserService } from '@core/http/user.service'; |
28 | import { MenuService } from '@core/services/menu.service'; | 28 | import { MenuService } from '@core/services/menu.service'; |
29 | -import { selectAuthUser, selectUserDetails } from '@core/auth/auth.selectors'; | 29 | +import { getCurrentAuthState, selectAuthUser, selectUserDetails } from '@core/auth/auth.selectors'; |
30 | import { MediaBreakpoints } from '@shared/models/constants'; | 30 | import { MediaBreakpoints } from '@shared/models/constants'; |
31 | import { ActionNotificationShow } from '@core/notification/notification.actions'; | 31 | import { ActionNotificationShow } from '@core/notification/notification.actions'; |
32 | import { Router } from '@angular/router'; | 32 | import { Router } from '@angular/router'; |
33 | import * as screenfull from 'screenfull'; | 33 | import * as screenfull from 'screenfull'; |
34 | import { MatSidenav } from '@angular/material'; | 34 | import { MatSidenav } from '@angular/material'; |
35 | +import { AuthState } from '@core/auth/auth.models'; | ||
36 | +import { WINDOW } from '@core/services/window.service'; | ||
35 | 37 | ||
36 | @Component({ | 38 | @Component({ |
37 | selector: 'tb-home', | 39 | selector: 'tb-home', |
@@ -40,6 +42,10 @@ import { MatSidenav } from '@angular/material'; | @@ -40,6 +42,10 @@ import { MatSidenav } from '@angular/material'; | ||
40 | }) | 42 | }) |
41 | export class HomeComponent extends PageComponent implements OnInit { | 43 | export class HomeComponent extends PageComponent implements OnInit { |
42 | 44 | ||
45 | + authState: AuthState = getCurrentAuthState(this.store); | ||
46 | + | ||
47 | + forceFullscreen = this.authState.forceFullscreen; | ||
48 | + | ||
43 | activeComponent: any; | 49 | activeComponent: any; |
44 | 50 | ||
45 | sidenavMode = 'side'; | 51 | sidenavMode = 'side'; |
@@ -58,6 +64,7 @@ export class HomeComponent extends PageComponent implements OnInit { | @@ -58,6 +64,7 @@ export class HomeComponent extends PageComponent implements OnInit { | ||
58 | userDetailsString: Observable<string>; | 64 | userDetailsString: Observable<string>; |
59 | 65 | ||
60 | constructor(protected store: Store<AppState>, | 66 | constructor(protected store: Store<AppState>, |
67 | + @Inject(WINDOW) private window: Window, | ||
61 | private authService: AuthService, | 68 | private authService: AuthService, |
62 | private router: Router, | 69 | private router: Router, |
63 | private userService: UserService, private menuService: MenuService, | 70 | private userService: UserService, private menuService: MenuService, |
@@ -110,4 +117,7 @@ export class HomeComponent extends PageComponent implements OnInit { | @@ -110,4 +117,7 @@ export class HomeComponent extends PageComponent implements OnInit { | ||
110 | return screenfull.isFullscreen; | 117 | return screenfull.isFullscreen; |
111 | } | 118 | } |
112 | 119 | ||
120 | + goBack() { | ||
121 | + this.window.history.back(); | ||
122 | + } | ||
113 | } | 123 | } |
@@ -31,6 +31,7 @@ import { | @@ -31,6 +31,7 @@ import { | ||
31 | } from '@shared/models/telemetry/telemetry.models'; | 31 | } from '@shared/models/telemetry/telemetry.models'; |
32 | import { AttributeService } from '@core/http/attribute.service'; | 32 | import { AttributeService } from '@core/http/attribute.service'; |
33 | import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; | 33 | import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; |
34 | +import { NgZone } from '@angular/core'; | ||
34 | 35 | ||
35 | export class AttributeDatasource implements DataSource<AttributeData> { | 36 | export class AttributeDatasource implements DataSource<AttributeData> { |
36 | 37 | ||
@@ -46,6 +47,7 @@ export class AttributeDatasource implements DataSource<AttributeData> { | @@ -46,6 +47,7 @@ export class AttributeDatasource implements DataSource<AttributeData> { | ||
46 | 47 | ||
47 | constructor(private attributeService: AttributeService, | 48 | constructor(private attributeService: AttributeService, |
48 | private telemetryWsService: TelemetryWebsocketService, | 49 | private telemetryWsService: TelemetryWebsocketService, |
50 | + private zone: NgZone, | ||
49 | private translate: TranslateService) {} | 51 | private translate: TranslateService) {} |
50 | 52 | ||
51 | connect(collectionViewer: CollectionViewer): Observable<AttributeData[] | ReadonlyArray<AttributeData>> { | 53 | connect(collectionViewer: CollectionViewer): Observable<AttributeData[] | ReadonlyArray<AttributeData>> { |
@@ -96,7 +98,7 @@ export class AttributeDatasource implements DataSource<AttributeData> { | @@ -96,7 +98,7 @@ export class AttributeDatasource implements DataSource<AttributeData> { | ||
96 | let attributesObservable: Observable<Array<AttributeData>>; | 98 | let attributesObservable: Observable<Array<AttributeData>>; |
97 | if (isClientSideTelemetryType.get(attributesScope)) { | 99 | if (isClientSideTelemetryType.get(attributesScope)) { |
98 | this.telemetrySubscriber = TelemetrySubscriber.createEntityAttributesSubscription( | 100 | this.telemetrySubscriber = TelemetrySubscriber.createEntityAttributesSubscription( |
99 | - this.telemetryWsService, entityId, attributesScope); | 101 | + this.telemetryWsService, entityId, attributesScope, this.zone); |
100 | this.telemetrySubscriber.subscribe(); | 102 | this.telemetrySubscriber.subscribe(); |
101 | attributesObservable = this.telemetrySubscriber.attributeData$(); | 103 | attributesObservable = this.telemetrySubscriber.attributeData$(); |
102 | } else { | 104 | } else { |
@@ -144,4 +146,5 @@ export class AttributeDatasource implements DataSource<AttributeData> { | @@ -144,4 +146,5 @@ export class AttributeDatasource implements DataSource<AttributeData> { | ||
144 | take(1) | 146 | take(1) |
145 | ).subscribe(); | 147 | ).subscribe(); |
146 | } | 148 | } |
149 | + | ||
147 | } | 150 | } |
@@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
19 | label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> | 19 | label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> |
20 | <tb-attribute-table [active]="attributesTab.isActive" | 20 | <tb-attribute-table [active]="attributesTab.isActive" |
21 | [entityId]="entity.id" | 21 | [entityId]="entity.id" |
22 | + [entityName]="entity.name" | ||
22 | [defaultAttributeScope]="attributeScopes.SERVER_SCOPE"> | 23 | [defaultAttributeScope]="attributeScopes.SERVER_SCOPE"> |
23 | </tb-attribute-table> | 24 | </tb-attribute-table> |
24 | </mat-tab> | 25 | </mat-tab> |
@@ -26,6 +27,7 @@ | @@ -26,6 +27,7 @@ | ||
26 | label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> | 27 | label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> |
27 | <tb-attribute-table [active]="telemetryTab.isActive" | 28 | <tb-attribute-table [active]="telemetryTab.isActive" |
28 | [entityId]="entity.id" | 29 | [entityId]="entity.id" |
30 | + [entityName]="entity.name" | ||
29 | [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" | 31 | [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" |
30 | disableAttributeScopeSelection> | 32 | disableAttributeScopeSelection> |
31 | </tb-attribute-table> | 33 | </tb-attribute-table> |
@@ -14,9 +14,9 @@ | @@ -14,9 +14,9 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import {Injectable} from '@angular/core'; | 17 | +import { Injectable } from '@angular/core'; |
18 | 18 | ||
19 | -import {ActivatedRouteSnapshot, Resolve, Router} from '@angular/router'; | 19 | +import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router'; |
20 | import { | 20 | import { |
21 | CellActionDescriptor, | 21 | CellActionDescriptor, |
22 | checkBoxCell, | 22 | checkBoxCell, |
@@ -26,22 +26,22 @@ import { | @@ -26,22 +26,22 @@ import { | ||
26 | GroupActionDescriptor, | 26 | GroupActionDescriptor, |
27 | HeaderActionDescriptor | 27 | HeaderActionDescriptor |
28 | } from '@home/models/entity/entities-table-config.models'; | 28 | } from '@home/models/entity/entities-table-config.models'; |
29 | -import {TranslateService} from '@ngx-translate/core'; | ||
30 | -import {DatePipe} from '@angular/common'; | ||
31 | -import {EntityType, entityTypeResources, entityTypeTranslations} from '@shared/models/entity-type.models'; | ||
32 | -import {EntityAction} from '@home/models/entity/entity-component.models'; | ||
33 | -import {forkJoin, Observable, of} from 'rxjs'; | ||
34 | -import {select, Store} from '@ngrx/store'; | ||
35 | -import {selectAuthUser} from '@core/auth/auth.selectors'; | ||
36 | -import {map, mergeMap, take, tap} from 'rxjs/operators'; | ||
37 | -import {AppState} from '@core/core.state'; | ||
38 | -import {Authority} from '@app/shared/models/authority.enum'; | ||
39 | -import {CustomerService} from '@core/http/customer.service'; | ||
40 | -import {Customer} from '@app/shared/models/customer.model'; | ||
41 | -import {NULL_UUID} from '@shared/models/id/has-uuid'; | ||
42 | -import {BroadcastService} from '@core/services/broadcast.service'; | ||
43 | -import {MatDialog} from '@angular/material'; | ||
44 | -import {DialogService} from '@core/services/dialog.service'; | 29 | +import { TranslateService } from '@ngx-translate/core'; |
30 | +import { DatePipe } from '@angular/common'; | ||
31 | +import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; | ||
32 | +import { EntityAction } from '@home/models/entity/entity-component.models'; | ||
33 | +import { forkJoin, Observable, of } from 'rxjs'; | ||
34 | +import { select, Store } from '@ngrx/store'; | ||
35 | +import { selectAuthUser } from '@core/auth/auth.selectors'; | ||
36 | +import { map, mergeMap, take, tap } from 'rxjs/operators'; | ||
37 | +import { AppState } from '@core/core.state'; | ||
38 | +import { Authority } from '@app/shared/models/authority.enum'; | ||
39 | +import { CustomerService } from '@core/http/customer.service'; | ||
40 | +import { Customer } from '@app/shared/models/customer.model'; | ||
41 | +import { NULL_UUID } from '@shared/models/id/has-uuid'; | ||
42 | +import { BroadcastService } from '@core/services/broadcast.service'; | ||
43 | +import { MatDialog } from '@angular/material'; | ||
44 | +import { DialogService } from '@core/services/dialog.service'; | ||
45 | import { | 45 | import { |
46 | AssignToCustomerDialogComponent, | 46 | AssignToCustomerDialogComponent, |
47 | AssignToCustomerDialogData | 47 | AssignToCustomerDialogData |
@@ -50,12 +50,13 @@ import { | @@ -50,12 +50,13 @@ import { | ||
50 | AddEntitiesToCustomerDialogComponent, | 50 | AddEntitiesToCustomerDialogComponent, |
51 | AddEntitiesToCustomerDialogData | 51 | AddEntitiesToCustomerDialogData |
52 | } from '../../dialogs/add-entities-to-customer-dialog.component'; | 52 | } from '../../dialogs/add-entities-to-customer-dialog.component'; |
53 | -import {Asset, AssetInfo} from '@app/shared/models/asset.models'; | ||
54 | -import {AssetService} from '@app/core/http/asset.service'; | ||
55 | -import {AssetComponent} from '@modules/home/pages/asset/asset.component'; | ||
56 | -import {AssetTableHeaderComponent} from '@modules/home/pages/asset/asset-table-header.component'; | ||
57 | -import {AssetId} from '@app/shared/models/id/asset-id'; | 53 | +import { Asset, AssetInfo } from '@app/shared/models/asset.models'; |
54 | +import { AssetService } from '@app/core/http/asset.service'; | ||
55 | +import { AssetComponent } from '@modules/home/pages/asset/asset.component'; | ||
56 | +import { AssetTableHeaderComponent } from '@modules/home/pages/asset/asset-table-header.component'; | ||
57 | +import { AssetId } from '@app/shared/models/id/asset-id'; | ||
58 | import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component'; | 58 | import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component'; |
59 | +import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; | ||
59 | 60 | ||
60 | @Injectable() | 61 | @Injectable() |
61 | export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> { | 62 | export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> { |
@@ -69,6 +70,7 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse | @@ -69,6 +70,7 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse | ||
69 | private assetService: AssetService, | 70 | private assetService: AssetService, |
70 | private customerService: CustomerService, | 71 | private customerService: CustomerService, |
71 | private dialogService: DialogService, | 72 | private dialogService: DialogService, |
73 | + private homeDialogs: HomeDialogsService, | ||
72 | private translate: TranslateService, | 74 | private translate: TranslateService, |
73 | private datePipe: DatePipe, | 75 | private datePipe: DatePipe, |
74 | private router: Router, | 76 | private router: Router, |
@@ -277,11 +279,12 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse | @@ -277,11 +279,12 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse | ||
277 | } | 279 | } |
278 | 280 | ||
279 | importAssets($event: Event) { | 281 | importAssets($event: Event) { |
280 | - if ($event) { | ||
281 | - $event.stopPropagation(); | ||
282 | - } | ||
283 | - // TODO: | ||
284 | - this.dialogService.todo(); | 282 | + this.homeDialogs.importEntities(EntityType.ASSET).subscribe((res) => { |
283 | + if (res) { | ||
284 | + this.broadcast.broadcast('assetSaved'); | ||
285 | + this.config.table.updateData(); | ||
286 | + } | ||
287 | + }); | ||
285 | } | 288 | } |
286 | 289 | ||
287 | addAssetsToCustomer($event: Event) { | 290 | addAssetsToCustomer($event: Event) { |
@@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
19 | label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> | 19 | label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> |
20 | <tb-attribute-table [active]="attributesTab.isActive" | 20 | <tb-attribute-table [active]="attributesTab.isActive" |
21 | [entityId]="entity.id" | 21 | [entityId]="entity.id" |
22 | + [entityName]="entity.name" | ||
22 | [defaultAttributeScope]="attributeScopes.SERVER_SCOPE"> | 23 | [defaultAttributeScope]="attributeScopes.SERVER_SCOPE"> |
23 | </tb-attribute-table> | 24 | </tb-attribute-table> |
24 | </mat-tab> | 25 | </mat-tab> |
@@ -26,6 +27,7 @@ | @@ -26,6 +27,7 @@ | ||
26 | label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> | 27 | label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> |
27 | <tb-attribute-table [active]="telemetryTab.isActive" | 28 | <tb-attribute-table [active]="telemetryTab.isActive" |
28 | [entityId]="entity.id" | 29 | [entityId]="entity.id" |
30 | + [entityName]="entity.name" | ||
29 | [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" | 31 | [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" |
30 | disableAttributeScopeSelection> | 32 | disableAttributeScopeSelection> |
31 | </tb-attribute-table> | 33 | </tb-attribute-table> |
@@ -32,7 +32,7 @@ | @@ -32,7 +32,7 @@ | ||
32 | (click)="closeToolbar()"> | 32 | (click)="closeToolbar()"> |
33 | <mat-icon>arrow_forward</mat-icon> | 33 | <mat-icon>arrow_forward</mat-icon> |
34 | </button> | 34 | </button> |
35 | - <tb-user-menu *ngIf="isPublicUser() && forceFullscreen" fxHide.xs fxHide.sm displayUserInfo="true"> | 35 | + <tb-user-menu *ngIf="!isPublicUser() && forceFullscreen" fxHide.xs fxHide.sm displayUserInfo="true"> |
36 | </tb-user-menu> | 36 | </tb-user-menu> |
37 | <button [fxShow]="showRightLayoutSwitch()" mat-button mat-icon-button | 37 | <button [fxShow]="showRightLayoutSwitch()" mat-button mat-icon-button |
38 | matTooltip="{{ (isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }}" | 38 | matTooltip="{{ (isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }}" |
@@ -45,7 +45,7 @@ import { | @@ -45,7 +45,7 @@ import { | ||
45 | import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; | 45 | import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; |
46 | import { MediaBreakpoints } from '@shared/models/constants'; | 46 | import { MediaBreakpoints } from '@shared/models/constants'; |
47 | import { AuthUser } from '@shared/models/user.model'; | 47 | import { AuthUser } from '@shared/models/user.model'; |
48 | -import { getCurrentAuthUser } from '@core/auth/auth.selectors'; | 48 | +import { getCurrentAuthState, getCurrentAuthUser } from '@core/auth/auth.selectors'; |
49 | import { Widget, WidgetConfig, WidgetPosition, widgetTypesData } from '@app/shared/models/widget.models'; | 49 | import { Widget, WidgetConfig, WidgetPosition, widgetTypesData } from '@app/shared/models/widget.models'; |
50 | import { environment as env } from '@env/environment'; | 50 | import { environment as env } from '@env/environment'; |
51 | import { Authority } from '@shared/models/authority.enum'; | 51 | import { Authority } from '@shared/models/authority.enum'; |
@@ -84,6 +84,7 @@ import { | @@ -84,6 +84,7 @@ import { | ||
84 | ManageDashboardStatesDialogData | 84 | ManageDashboardStatesDialogData |
85 | } from '@home/pages/dashboard/states/manage-dashboard-states-dialog.component'; | 85 | } from '@home/pages/dashboard/states/manage-dashboard-states-dialog.component'; |
86 | import { ImportExportService } from '@home/components/import-export/import-export.service'; | 86 | import { ImportExportService } from '@home/components/import-export/import-export.service'; |
87 | +import { AuthState } from '@app/core/auth/auth.models'; | ||
87 | 88 | ||
88 | @Component({ | 89 | @Component({ |
89 | selector: 'tb-dashboard-page', | 90 | selector: 'tb-dashboard-page', |
@@ -94,7 +95,9 @@ import { ImportExportService } from '@home/components/import-export/import-expor | @@ -94,7 +95,9 @@ import { ImportExportService } from '@home/components/import-export/import-expor | ||
94 | }) | 95 | }) |
95 | export class DashboardPageComponent extends PageComponent implements IDashboardController, OnDestroy { | 96 | export class DashboardPageComponent extends PageComponent implements IDashboardController, OnDestroy { |
96 | 97 | ||
97 | - authUser: AuthUser = getCurrentAuthUser(this.store); | 98 | + authState: AuthState = getCurrentAuthState(this.store); |
99 | + | ||
100 | + authUser: AuthUser = this.authState.authUser; | ||
98 | 101 | ||
99 | dashboard: Dashboard; | 102 | dashboard: Dashboard; |
100 | dashboardConfiguration: DashboardConfiguration; | 103 | dashboardConfiguration: DashboardConfiguration; |
@@ -104,7 +107,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | @@ -104,7 +107,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | ||
104 | iframeMode = this.utils.iframeMode; | 107 | iframeMode = this.utils.iframeMode; |
105 | widgetEditMode: boolean; | 108 | widgetEditMode: boolean; |
106 | singlePageMode: boolean; | 109 | singlePageMode: boolean; |
107 | - forceFullscreen = this.authService.forceFullscreen; | 110 | + forceFullscreen = this.authState.forceFullscreen; |
108 | 111 | ||
109 | isFullscreen = false; | 112 | isFullscreen = false; |
110 | isEdit = false; | 113 | isEdit = false; |
@@ -36,6 +36,7 @@ import { SelectTargetLayoutDialogComponent } from './layout/select-target-layout | @@ -36,6 +36,7 @@ import { SelectTargetLayoutDialogComponent } from './layout/select-target-layout | ||
36 | import { DashboardSettingsDialogComponent } from './dashboard-settings-dialog.component'; | 36 | import { DashboardSettingsDialogComponent } from './dashboard-settings-dialog.component'; |
37 | import { ManageDashboardStatesDialogComponent } from './states/manage-dashboard-states-dialog.component'; | 37 | import { ManageDashboardStatesDialogComponent } from './states/manage-dashboard-states-dialog.component'; |
38 | import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.component'; | 38 | import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.component'; |
39 | +import { SelectTargetStateDialogComponent } from './states/select-target-state-dialog.component'; | ||
39 | 40 | ||
40 | @NgModule({ | 41 | @NgModule({ |
41 | entryComponents: [ | 42 | entryComponents: [ |
@@ -48,7 +49,8 @@ import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.c | @@ -48,7 +49,8 @@ import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.c | ||
48 | SelectTargetLayoutDialogComponent, | 49 | SelectTargetLayoutDialogComponent, |
49 | DashboardSettingsDialogComponent, | 50 | DashboardSettingsDialogComponent, |
50 | ManageDashboardStatesDialogComponent, | 51 | ManageDashboardStatesDialogComponent, |
51 | - DashboardStateDialogComponent | 52 | + DashboardStateDialogComponent, |
53 | + SelectTargetStateDialogComponent | ||
52 | ], | 54 | ], |
53 | declarations: [ | 55 | declarations: [ |
54 | DashboardFormComponent, | 56 | DashboardFormComponent, |
@@ -65,7 +67,8 @@ import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.c | @@ -65,7 +67,8 @@ import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.c | ||
65 | SelectTargetLayoutDialogComponent, | 67 | SelectTargetLayoutDialogComponent, |
66 | DashboardSettingsDialogComponent, | 68 | DashboardSettingsDialogComponent, |
67 | ManageDashboardStatesDialogComponent, | 69 | ManageDashboardStatesDialogComponent, |
68 | - DashboardStateDialogComponent | 70 | + DashboardStateDialogComponent, |
71 | + SelectTargetStateDialogComponent | ||
69 | ], | 72 | ], |
70 | imports: [ | 73 | imports: [ |
71 | CommonModule, | 74 | CommonModule, |
@@ -301,7 +301,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp | @@ -301,7 +301,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp | ||
301 | return of(params.entityName); | 301 | return of(params.entityName); |
302 | } else { | 302 | } else { |
303 | return this.entityService.getEntity(params.entityId.entityType as EntityType, | 303 | return this.entityService.getEntity(params.entityId.entityType as EntityType, |
304 | - params.entityId.id, true, true).pipe( | 304 | + params.entityId.id, {ignoreLoading: true, ignoreErrors: true}).pipe( |
305 | map((entity) => entity.name) | 305 | map((entity) => entity.name) |
306 | ); | 306 | ); |
307 | } | 307 | } |
ui-ngx/src/app/modules/home/pages/dashboard/states/select-target-state-dialog.component.html
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<form #stateForm="ngForm" [formGroup]="stateFormGroup" (ngSubmit)="save()"> | ||
19 | + <mat-toolbar fxLayout="row" color="primary"> | ||
20 | + <h2 translate>dashboard.select-state</h2> | ||
21 | + <span fxFlex></span> | ||
22 | + <button mat-button mat-icon-button | ||
23 | + (click)="cancel()" | ||
24 | + type="button"> | ||
25 | + <mat-icon class="material-icons">close</mat-icon> | ||
26 | + </button> | ||
27 | + </mat-toolbar> | ||
28 | + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> | ||
29 | + </mat-progress-bar> | ||
30 | + <div mat-dialog-content> | ||
31 | + <fieldset [disabled]="isLoading$ | async" fxLayout="column"> | ||
32 | + <mat-form-field class="mat-block"> | ||
33 | + <mat-label translate>dashboard.state</mat-label> | ||
34 | + <mat-select required matInput formControlName="stateId"> | ||
35 | + <mat-option *ngFor="let stateItem of states | keyvalue" [value]="stateItem.key"> | ||
36 | + {{ stateItem.value.name }} | ||
37 | + </mat-option> | ||
38 | + </mat-select> | ||
39 | + </mat-form-field> | ||
40 | + </fieldset> | ||
41 | + </div> | ||
42 | + <div mat-dialog-actions fxLayout="row"> | ||
43 | + <span fxFlex></span> | ||
44 | + <button mat-button mat-raised-button color="primary" | ||
45 | + type="submit" | ||
46 | + [disabled]="(isLoading$ | async) || stateFormGroup.invalid"> | ||
47 | + {{ 'action.select' | translate }} | ||
48 | + </button> | ||
49 | + <button mat-button color="primary" | ||
50 | + style="margin-right: 20px;" | ||
51 | + type="button" | ||
52 | + [disabled]="(isLoading$ | async)" | ||
53 | + (click)="cancel()" cdkFocusInitial> | ||
54 | + {{ 'action.cancel' | translate }} | ||
55 | + </button> | ||
56 | + </div> | ||
57 | +</form> |
ui-ngx/src/app/modules/home/pages/dashboard/states/select-target-state-dialog.component.ts
0 → 100644
1 | +/// | ||
2 | +/// Copyright © 2016-2019 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; | ||
18 | +import { ErrorStateMatcher, MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; | ||
19 | +import { Store } from '@ngrx/store'; | ||
20 | +import { AppState } from '@core/core.state'; | ||
21 | +import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; | ||
22 | +import { Router } from '@angular/router'; | ||
23 | +import { DialogComponent } from '@app/shared/components/dialog.component'; | ||
24 | +import { UtilsService } from '@core/services/utils.service'; | ||
25 | +import { TranslateService } from '@ngx-translate/core'; | ||
26 | +import { DashboardState } from '@app/shared/models/dashboard.models'; | ||
27 | +import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; | ||
28 | +import { DashboardService } from '@core/http/dashboard.service'; | ||
29 | + | ||
30 | +export interface SelectTargetStateDialogData { | ||
31 | + states: {[id: string]: DashboardState }; | ||
32 | +} | ||
33 | + | ||
34 | +@Component({ | ||
35 | + selector: 'tb-select-target-state-dialog', | ||
36 | + templateUrl: './select-target-state-dialog.component.html', | ||
37 | + providers: [{provide: ErrorStateMatcher, useExisting: SelectTargetStateDialogComponent}], | ||
38 | + styleUrls: [] | ||
39 | +}) | ||
40 | +export class SelectTargetStateDialogComponent extends | ||
41 | + DialogComponent<SelectTargetStateDialogComponent, string> | ||
42 | + implements OnInit, ErrorStateMatcher { | ||
43 | + | ||
44 | + states: {[id: string]: DashboardState }; | ||
45 | + stateFormGroup: FormGroup; | ||
46 | + | ||
47 | + submitted = false; | ||
48 | + | ||
49 | + constructor(protected store: Store<AppState>, | ||
50 | + protected router: Router, | ||
51 | + @Inject(MAT_DIALOG_DATA) public data: SelectTargetStateDialogData, | ||
52 | + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, | ||
53 | + public dialogRef: MatDialogRef<SelectTargetStateDialogComponent, string>, | ||
54 | + private fb: FormBuilder, | ||
55 | + private dashboardUtils: DashboardUtilsService) { | ||
56 | + super(store, router, dialogRef); | ||
57 | + | ||
58 | + this.states = this.data.states; | ||
59 | + | ||
60 | + this.stateFormGroup = this.fb.group( | ||
61 | + { | ||
62 | + stateId: [this.dashboardUtils.getRootStateId(this.states), [Validators.required]] | ||
63 | + } | ||
64 | + ); | ||
65 | + } | ||
66 | + | ||
67 | + ngOnInit(): void { | ||
68 | + } | ||
69 | + | ||
70 | + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { | ||
71 | + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); | ||
72 | + const customErrorState = !!(control && control.invalid && this.submitted); | ||
73 | + return originalErrorState || customErrorState; | ||
74 | + } | ||
75 | + | ||
76 | + cancel(): void { | ||
77 | + this.dialogRef.close(null); | ||
78 | + } | ||
79 | + | ||
80 | + save(): void { | ||
81 | + this.submitted = true; | ||
82 | + const stateId: string = this.stateFormGroup.get('stateId').value; | ||
83 | + this.dialogRef.close(stateId); | ||
84 | + } | ||
85 | +} |
@@ -60,9 +60,10 @@ export abstract class StateControllerComponent implements IStateControllerCompon | @@ -60,9 +60,10 @@ export abstract class StateControllerComponent implements IStateControllerCompon | ||
60 | set dashboardId(val: string) { | 60 | set dashboardId(val: string) { |
61 | if (this.dashboardIdValue !== val) { | 61 | if (this.dashboardIdValue !== val) { |
62 | this.dashboardIdValue = val; | 62 | this.dashboardIdValue = val; |
63 | - if (this.inited) { | 63 | +/* if (this.inited) { |
64 | + this.currentState = this.route.snapshot.queryParamMap.get('state'); | ||
64 | this.init(); | 65 | this.init(); |
65 | - } | 66 | + }*/ |
66 | } | 67 | } |
67 | } | 68 | } |
68 | get dashboardId(): string { | 69 | get dashboardId(): string { |
@@ -84,8 +85,6 @@ export abstract class StateControllerComponent implements IStateControllerCompon | @@ -84,8 +85,6 @@ export abstract class StateControllerComponent implements IStateControllerCompon | ||
84 | 85 | ||
85 | currentState: string; | 86 | currentState: string; |
86 | 87 | ||
87 | - currentUrl: string; | ||
88 | - | ||
89 | private rxSubscriptions = new Array<Subscription>(); | 88 | private rxSubscriptions = new Array<Subscription>(); |
90 | 89 | ||
91 | private inited = false; | 90 | private inited = false; |
@@ -96,10 +95,9 @@ export abstract class StateControllerComponent implements IStateControllerCompon | @@ -96,10 +95,9 @@ export abstract class StateControllerComponent implements IStateControllerCompon | ||
96 | } | 95 | } |
97 | 96 | ||
98 | ngOnInit(): void { | 97 | ngOnInit(): void { |
99 | - this.currentUrl = this.router.url.split('?')[0]; | ||
100 | this.rxSubscriptions.push(this.route.queryParamMap.subscribe((paramMap) => { | 98 | this.rxSubscriptions.push(this.route.queryParamMap.subscribe((paramMap) => { |
101 | - const newUrl = this.router.url.split('?')[0]; | ||
102 | - if (this.currentUrl === newUrl) { | 99 | + const dashboardId = this.route.snapshot.params.dashboardId; |
100 | + if (this.dashboardId === dashboardId) { | ||
103 | const newState = paramMap.get('state'); | 101 | const newState = paramMap.get('state'); |
104 | if (this.currentState !== newState) { | 102 | if (this.currentState !== newState) { |
105 | this.currentState = newState; | 103 | this.currentState = newState; |
@@ -144,6 +142,11 @@ export abstract class StateControllerComponent implements IStateControllerCompon | @@ -144,6 +142,11 @@ export abstract class StateControllerComponent implements IStateControllerCompon | ||
144 | this.statesControllerService.cleanupPreservedStates(); | 142 | this.statesControllerService.cleanupPreservedStates(); |
145 | } | 143 | } |
146 | 144 | ||
145 | + public reInit() { | ||
146 | + this.currentState = this.route.snapshot.queryParamMap.get('state'); | ||
147 | + this.init(); | ||
148 | + } | ||
149 | + | ||
147 | protected abstract init(); | 150 | protected abstract init(); |
148 | 151 | ||
149 | protected abstract onMobileChanged(); | 152 | protected abstract onMobileChanged(); |
@@ -27,4 +27,5 @@ export interface IStateControllerComponent extends IStateController { | @@ -27,4 +27,5 @@ export interface IStateControllerComponent extends IStateController { | ||
27 | states: {[id: string]: DashboardState }; | 27 | states: {[id: string]: DashboardState }; |
28 | dashboardId: string; | 28 | dashboardId: string; |
29 | preservedState: any; | 29 | preservedState: any; |
30 | + reInit(): void; | ||
30 | } | 31 | } |
@@ -72,6 +72,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { | @@ -72,6 +72,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { | ||
72 | } | 72 | } |
73 | 73 | ||
74 | ngOnChanges(changes: SimpleChanges): void { | 74 | ngOnChanges(changes: SimpleChanges): void { |
75 | + let reInitController = false; | ||
75 | for (const propName of Object.keys(changes)) { | 76 | for (const propName of Object.keys(changes)) { |
76 | const change = changes[propName]; | 77 | const change = changes[propName]; |
77 | if (!change.firstChange && change.currentValue !== change.previousValue) { | 78 | if (!change.firstChange && change.currentValue !== change.previousValue) { |
@@ -81,6 +82,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { | @@ -81,6 +82,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { | ||
81 | this.stateControllerComponent.states = this.states; | 82 | this.stateControllerComponent.states = this.states; |
82 | } else if (propName === 'dashboardId') { | 83 | } else if (propName === 'dashboardId') { |
83 | this.stateControllerComponent.dashboardId = this.dashboardId; | 84 | this.stateControllerComponent.dashboardId = this.dashboardId; |
85 | + reInitController = true; | ||
84 | } else if (propName === 'isMobile') { | 86 | } else if (propName === 'isMobile') { |
85 | this.stateControllerComponent.isMobile = this.isMobile; | 87 | this.stateControllerComponent.isMobile = this.isMobile; |
86 | } else if (propName === 'state') { | 88 | } else if (propName === 'state') { |
@@ -88,6 +90,9 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { | @@ -88,6 +90,9 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { | ||
88 | } | 90 | } |
89 | } | 91 | } |
90 | } | 92 | } |
93 | + if (reInitController) { | ||
94 | + this.stateControllerComponent.reInit(); | ||
95 | + } | ||
91 | } | 96 | } |
92 | 97 | ||
93 | private reInit() { | 98 | private reInit() { |
@@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
19 | label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> | 19 | label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> |
20 | <tb-attribute-table [active]="attributesTab.isActive" | 20 | <tb-attribute-table [active]="attributesTab.isActive" |
21 | [entityId]="entity.id" | 21 | [entityId]="entity.id" |
22 | + [entityName]="entity.name" | ||
22 | [defaultAttributeScope]="attributeScopes.CLIENT_SCOPE"> | 23 | [defaultAttributeScope]="attributeScopes.CLIENT_SCOPE"> |
23 | </tb-attribute-table> | 24 | </tb-attribute-table> |
24 | </mat-tab> | 25 | </mat-tab> |
@@ -26,6 +27,7 @@ | @@ -26,6 +27,7 @@ | ||
26 | label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> | 27 | label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> |
27 | <tb-attribute-table [active]="telemetryTab.isActive" | 28 | <tb-attribute-table [active]="telemetryTab.isActive" |
28 | [entityId]="entity.id" | 29 | [entityId]="entity.id" |
30 | + [entityName]="entity.name" | ||
29 | [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" | 31 | [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" |
30 | disableAttributeScopeSelection> | 32 | disableAttributeScopeSelection> |
31 | </tb-attribute-table> | 33 | </tb-attribute-table> |