Commit 3d6b058b9dbaf485994bc68a98d6b9c71b9d0530
1 parent
65b7c139
Add widget to dashboard. CSV bulk import. User default place management.
Showing
89 changed files
with
2775 additions
and
579 deletions
@@ -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> |
@@ -14,51 +14,53 @@ | @@ -14,51 +14,53 @@ | ||
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, |
23 | DateEntityTableColumn, | 23 | DateEntityTableColumn, |
24 | EntityTableColumn, | 24 | EntityTableColumn, |
25 | - EntityTableConfig, GroupActionDescriptor, | 25 | + EntityTableConfig, |
26 | + GroupActionDescriptor, | ||
26 | HeaderActionDescriptor | 27 | HeaderActionDescriptor |
27 | } from '@home/models/entity/entities-table-config.models'; | 28 | } from '@home/models/entity/entities-table-config.models'; |
28 | -import {TranslateService} from '@ngx-translate/core'; | ||
29 | -import {DatePipe} from '@angular/common'; | ||
30 | -import {EntityType, entityTypeResources, entityTypeTranslations} from '@shared/models/entity-type.models'; | ||
31 | -import {EntityAction} from '@home/models/entity/entity-component.models'; | ||
32 | -import {Device, DeviceCredentials, DeviceInfo} from '@app/shared/models/device.models'; | ||
33 | -import {DeviceComponent} from '@modules/home/pages/device/device.component'; | ||
34 | -import {forkJoin, Observable, of} from 'rxjs'; | ||
35 | -import {select, Store} from '@ngrx/store'; | ||
36 | -import {selectAuthUser} from '@core/auth/auth.selectors'; | ||
37 | -import {map, mergeMap, take, tap} from 'rxjs/operators'; | ||
38 | -import {AppState} from '@core/core.state'; | ||
39 | -import {DeviceService} from '@app/core/http/device.service'; | ||
40 | -import {Authority} from '@app/shared/models/authority.enum'; | ||
41 | -import {CustomerService} from '@core/http/customer.service'; | ||
42 | -import {Customer} from '@app/shared/models/customer.model'; | ||
43 | -import {NULL_UUID} from '@shared/models/id/has-uuid'; | ||
44 | -import {BroadcastService} from '@core/services/broadcast.service'; | ||
45 | -import {DeviceTableHeaderComponent} from '@modules/home/pages/device/device-table-header.component'; | ||
46 | -import {MatDialog} from '@angular/material'; | 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 { Device, DeviceCredentials, DeviceInfo } from '@app/shared/models/device.models'; | ||
34 | +import { DeviceComponent } from '@modules/home/pages/device/device.component'; | ||
35 | +import { forkJoin, Observable, of } from 'rxjs'; | ||
36 | +import { select, Store } from '@ngrx/store'; | ||
37 | +import { selectAuthUser } from '@core/auth/auth.selectors'; | ||
38 | +import { map, mergeMap, take, tap } from 'rxjs/operators'; | ||
39 | +import { AppState } from '@core/core.state'; | ||
40 | +import { DeviceService } from '@app/core/http/device.service'; | ||
41 | +import { Authority } from '@app/shared/models/authority.enum'; | ||
42 | +import { CustomerService } from '@core/http/customer.service'; | ||
43 | +import { Customer } from '@app/shared/models/customer.model'; | ||
44 | +import { NULL_UUID } from '@shared/models/id/has-uuid'; | ||
45 | +import { BroadcastService } from '@core/services/broadcast.service'; | ||
46 | +import { DeviceTableHeaderComponent } from '@modules/home/pages/device/device-table-header.component'; | ||
47 | +import { MatDialog } from '@angular/material'; | ||
47 | import { | 48 | import { |
48 | DeviceCredentialsDialogComponent, | 49 | DeviceCredentialsDialogComponent, |
49 | DeviceCredentialsDialogData | 50 | DeviceCredentialsDialogData |
50 | } from '@modules/home/pages/device/device-credentials-dialog.component'; | 51 | } from '@modules/home/pages/device/device-credentials-dialog.component'; |
51 | -import {DialogService} from '@core/services/dialog.service'; | 52 | +import { DialogService } from '@core/services/dialog.service'; |
52 | import { | 53 | import { |
53 | AssignToCustomerDialogComponent, | 54 | AssignToCustomerDialogComponent, |
54 | AssignToCustomerDialogData | 55 | AssignToCustomerDialogData |
55 | } from '@modules/home/dialogs/assign-to-customer-dialog.component'; | 56 | } from '@modules/home/dialogs/assign-to-customer-dialog.component'; |
56 | -import {DeviceId} from '@app/shared/models/id/device-id'; | 57 | +import { DeviceId } from '@app/shared/models/id/device-id'; |
57 | import { | 58 | import { |
58 | AddEntitiesToCustomerDialogComponent, | 59 | AddEntitiesToCustomerDialogComponent, |
59 | AddEntitiesToCustomerDialogData | 60 | AddEntitiesToCustomerDialogData |
60 | } from '../../dialogs/add-entities-to-customer-dialog.component'; | 61 | } from '../../dialogs/add-entities-to-customer-dialog.component'; |
61 | import { DeviceTabsComponent } from '@home/pages/device/device-tabs.component'; | 62 | import { DeviceTabsComponent } from '@home/pages/device/device-tabs.component'; |
63 | +import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; | ||
62 | 64 | ||
63 | @Injectable() | 65 | @Injectable() |
64 | export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<DeviceInfo>> { | 66 | export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<DeviceInfo>> { |
@@ -72,6 +74,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev | @@ -72,6 +74,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev | ||
72 | private deviceService: DeviceService, | 74 | private deviceService: DeviceService, |
73 | private customerService: CustomerService, | 75 | private customerService: CustomerService, |
74 | private dialogService: DialogService, | 76 | private dialogService: DialogService, |
77 | + private homeDialogs: HomeDialogsService, | ||
75 | private translate: TranslateService, | 78 | private translate: TranslateService, |
76 | private datePipe: DatePipe, | 79 | private datePipe: DatePipe, |
77 | private router: Router, | 80 | private router: Router, |
@@ -309,11 +312,12 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev | @@ -309,11 +312,12 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev | ||
309 | } | 312 | } |
310 | 313 | ||
311 | importDevices($event: Event) { | 314 | importDevices($event: Event) { |
312 | - if ($event) { | ||
313 | - $event.stopPropagation(); | ||
314 | - } | ||
315 | - // TODO: | ||
316 | - this.dialogService.todo(); | 315 | + this.homeDialogs.importEntities(EntityType.DEVICE).subscribe((res) => { |
316 | + if (res) { | ||
317 | + this.broadcast.broadcast('deviceSaved'); | ||
318 | + this.config.table.updateData(); | ||
319 | + } | ||
320 | + }); | ||
317 | } | 321 | } |
318 | 322 | ||
319 | addDevicesToCustomer($event: Event) { | 323 | addDevicesToCustomer($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.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> |
@@ -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> |
@@ -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> |
@@ -29,7 +29,10 @@ import { FormBuilder } from '@angular/forms'; | @@ -29,7 +29,10 @@ import { FormBuilder } from '@angular/forms'; | ||
29 | }) | 29 | }) |
30 | export class LoginComponent extends PageComponent implements OnInit { | 30 | export class LoginComponent extends PageComponent implements OnInit { |
31 | 31 | ||
32 | - loginFormGroup = this.fb.group(new LoginRequest('', '')); | 32 | + loginFormGroup = this.fb.group({ |
33 | + username: '', | ||
34 | + password: '' | ||
35 | + }); | ||
33 | 36 | ||
34 | constructor(protected store: Store<AppState>, | 37 | constructor(protected store: Store<AppState>, |
35 | private authService: AuthService, | 38 | private authService: AuthService, |
@@ -192,19 +192,22 @@ export class DashboardAutocompleteComponent implements ControlValueAccessor, OnI | @@ -192,19 +192,22 @@ export class DashboardAutocompleteComponent implements ControlValueAccessor, OnI | ||
192 | const authUser = getCurrentAuthUser(this.store); | 192 | const authUser = getCurrentAuthUser(this.store); |
193 | if (this.dashboardsScope === 'customer' || authUser.authority === Authority.CUSTOMER_USER) { | 193 | if (this.dashboardsScope === 'customer' || authUser.authority === Authority.CUSTOMER_USER) { |
194 | if (this.customerId) { | 194 | if (this.customerId) { |
195 | - dashboardsObservable = this.dashboardService.getCustomerDashboards(this.customerId, pageLink, false, true); | 195 | + dashboardsObservable = this.dashboardService.getCustomerDashboards(this.customerId, pageLink, |
196 | + {ignoreLoading: true}); | ||
196 | } else { | 197 | } else { |
197 | dashboardsObservable = of(emptyPageData()); | 198 | dashboardsObservable = of(emptyPageData()); |
198 | } | 199 | } |
199 | } else { | 200 | } else { |
200 | if (authUser.authority === Authority.SYS_ADMIN) { | 201 | if (authUser.authority === Authority.SYS_ADMIN) { |
201 | if (this.tenantId) { | 202 | if (this.tenantId) { |
202 | - dashboardsObservable = this.dashboardService.getTenantDashboardsByTenantId(this.tenantId, pageLink, false, true); | 203 | + dashboardsObservable = this.dashboardService.getTenantDashboardsByTenantId(this.tenantId, pageLink, |
204 | + {ignoreLoading: true}); | ||
203 | } else { | 205 | } else { |
204 | dashboardsObservable = of(emptyPageData()); | 206 | dashboardsObservable = of(emptyPageData()); |
205 | } | 207 | } |
206 | } else { | 208 | } else { |
207 | - dashboardsObservable = this.dashboardService.getTenantDashboards(pageLink, false, true); | 209 | + dashboardsObservable = this.dashboardService.getTenantDashboards(pageLink, |
210 | + {ignoreLoading: true}); | ||
208 | } | 211 | } |
209 | } | 212 | } |
210 | return dashboardsObservable; | 213 | return dashboardsObservable; |
@@ -202,12 +202,13 @@ export class DashboardSelectComponent implements ControlValueAccessor, OnInit { | @@ -202,12 +202,13 @@ export class DashboardSelectComponent implements ControlValueAccessor, OnInit { | ||
202 | const authUser = getCurrentAuthUser(this.store); | 202 | const authUser = getCurrentAuthUser(this.store); |
203 | if (this.dashboardsScope === 'customer' || authUser.authority === Authority.CUSTOMER_USER) { | 203 | if (this.dashboardsScope === 'customer' || authUser.authority === Authority.CUSTOMER_USER) { |
204 | if (this.customerId && this.customerId !== NULL_UUID) { | 204 | if (this.customerId && this.customerId !== NULL_UUID) { |
205 | - dashboardsObservable = this.dashboardService.getCustomerDashboards(this.customerId, pageLink, false, true); | 205 | + dashboardsObservable = this.dashboardService.getCustomerDashboards(this.customerId, pageLink, |
206 | + {ignoreLoading: true}); | ||
206 | } else { | 207 | } else { |
207 | dashboardsObservable = of(emptyPageData()); | 208 | dashboardsObservable = of(emptyPageData()); |
208 | } | 209 | } |
209 | } else { | 210 | } else { |
210 | - dashboardsObservable = this.dashboardService.getTenantDashboards(pageLink, false, true); | 211 | + dashboardsObservable = this.dashboardService.getTenantDashboards(pageLink, {ignoreLoading: true}); |
211 | } | 212 | } |
212 | return dashboardsObservable; | 213 | return dashboardsObservable; |
213 | } | 214 | } |
@@ -230,7 +230,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit | @@ -230,7 +230,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit | ||
230 | if (targetEntityType === AliasEntityType.CURRENT_CUSTOMER) { | 230 | if (targetEntityType === AliasEntityType.CURRENT_CUSTOMER) { |
231 | targetEntityType = EntityType.CUSTOMER; | 231 | targetEntityType = EntityType.CUSTOMER; |
232 | } | 232 | } |
233 | - this.entityService.getEntity(targetEntityType, value, true).subscribe( | 233 | + this.entityService.getEntity(targetEntityType, value, {ignoreLoading: true}).subscribe( |
234 | (entity) => { | 234 | (entity) => { |
235 | this.modelValue = entity.id.id; | 235 | this.modelValue = entity.id.id; |
236 | this.selectEntityFormGroup.get('entity').patchValue(entity, {emitEvent: false}); | 236 | this.selectEntityFormGroup.get('entity').patchValue(entity, {emitEvent: false}); |
@@ -238,7 +238,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit | @@ -238,7 +238,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit | ||
238 | ); | 238 | ); |
239 | } else { | 239 | } else { |
240 | const targetEntityType = value.entityType as EntityType; | 240 | const targetEntityType = value.entityType as EntityType; |
241 | - this.entityService.getEntity(targetEntityType, value.id, true).subscribe( | 241 | + this.entityService.getEntity(targetEntityType, value.id, {ignoreLoading: true}).subscribe( |
242 | (entity) => { | 242 | (entity) => { |
243 | this.modelValue = entity.id.id; | 243 | this.modelValue = entity.id.id; |
244 | this.selectEntityFormGroup.get('entity').patchValue(entity, {emitEvent: false}); | 244 | this.selectEntityFormGroup.get('entity').patchValue(entity, {emitEvent: false}); |
@@ -281,7 +281,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit | @@ -281,7 +281,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit | ||
281 | targetEntityType = EntityType.CUSTOMER; | 281 | targetEntityType = EntityType.CUSTOMER; |
282 | } | 282 | } |
283 | return this.entityService.getEntitiesByNameFilter(targetEntityType, searchText, | 283 | return this.entityService.getEntitiesByNameFilter(targetEntityType, searchText, |
284 | - 50, this.entitySubtypeValue, false, true).pipe( | 284 | + 50, this.entitySubtypeValue, {ignoreLoading: true}).pipe( |
285 | map((data) => { | 285 | map((data) => { |
286 | if (data) { | 286 | if (data) { |
287 | if (this.excludeEntityIds && this.excludeEntityIds.length) { | 287 | if (this.excludeEntityIds && this.excludeEntityIds.length) { |
@@ -198,7 +198,7 @@ export class EntityKeysListComponent implements ControlValueAccessor, OnInit, Af | @@ -198,7 +198,7 @@ export class EntityKeysListComponent implements ControlValueAccessor, OnInit, Af | ||
198 | fetchKeys(searchText?: string): Observable<Array<string>> { | 198 | fetchKeys(searchText?: string): Observable<Array<string>> { |
199 | this.searchText = searchText; | 199 | this.searchText = searchText; |
200 | return this.entityIdValue ? this.entityService.getEntityKeys(this.entityIdValue, searchText, | 200 | return this.entityIdValue ? this.entityService.getEntityKeys(this.entityIdValue, searchText, |
201 | - this.dataKeyType, false, true).pipe( | 201 | + this.dataKeyType, {ignoreLoading: true}).pipe( |
202 | map((data) => data ? data : [])) : of([]); | 202 | map((data) => data ? data : [])) : of([]); |
203 | } | 203 | } |
204 | 204 |
@@ -223,7 +223,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV | @@ -223,7 +223,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV | ||
223 | fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> { | 223 | fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> { |
224 | this.searchText = searchText; | 224 | this.searchText = searchText; |
225 | return this.entityService.getEntitiesByNameFilter(this.entityType, searchText, | 225 | return this.entityService.getEntitiesByNameFilter(this.entityType, searchText, |
226 | - 50, '', false, true).pipe( | 226 | + 50, '', {ignoreLoading: true}).pipe( |
227 | map((data) => data ? data : [])); | 227 | map((data) => data ? data : [])); |
228 | } | 228 | } |
229 | 229 |
@@ -205,13 +205,13 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, | @@ -205,13 +205,13 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, | ||
205 | let subTypesObservable: Observable<Array<EntitySubtype>>; | 205 | let subTypesObservable: Observable<Array<EntitySubtype>>; |
206 | switch (this.entityType) { | 206 | switch (this.entityType) { |
207 | case EntityType.ASSET: | 207 | case EntityType.ASSET: |
208 | - subTypesObservable = this.assetService.getAssetTypes(false, true); | 208 | + subTypesObservable = this.assetService.getAssetTypes({ignoreLoading: true}); |
209 | break; | 209 | break; |
210 | case EntityType.DEVICE: | 210 | case EntityType.DEVICE: |
211 | - subTypesObservable = this.deviceService.getDeviceTypes(false, true); | 211 | + subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true}); |
212 | break; | 212 | break; |
213 | case EntityType.ENTITY_VIEW: | 213 | case EntityType.ENTITY_VIEW: |
214 | - subTypesObservable = this.entityViewService.getEntityViewTypes(false, true); | 214 | + subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true}); |
215 | break; | 215 | break; |
216 | } | 216 | } |
217 | if (subTypesObservable) { | 217 | if (subTypesObservable) { |
@@ -276,13 +276,13 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, | @@ -276,13 +276,13 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, | ||
276 | let subTypesObservable: Observable<Array<EntitySubtype>>; | 276 | let subTypesObservable: Observable<Array<EntitySubtype>>; |
277 | switch (this.entityType) { | 277 | switch (this.entityType) { |
278 | case EntityType.ASSET: | 278 | case EntityType.ASSET: |
279 | - subTypesObservable = this.assetService.getAssetTypes(false, true); | 279 | + subTypesObservable = this.assetService.getAssetTypes({ignoreLoading: true}); |
280 | break; | 280 | break; |
281 | case EntityType.DEVICE: | 281 | case EntityType.DEVICE: |
282 | - subTypesObservable = this.deviceService.getDeviceTypes(false, true); | 282 | + subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true}); |
283 | break; | 283 | break; |
284 | case EntityType.ENTITY_VIEW: | 284 | case EntityType.ENTITY_VIEW: |
285 | - subTypesObservable = this.entityViewService.getEntityViewTypes(false, true); | 285 | + subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true}); |
286 | break; | 286 | break; |
287 | } | 287 | } |
288 | if (subTypesObservable) { | 288 | if (subTypesObservable) { |
@@ -17,8 +17,7 @@ | @@ -17,8 +17,7 @@ | ||
17 | --> | 17 | --> |
18 | <mat-form-field [formGroup]="subTypeFormGroup" class="mat-block"> | 18 | <mat-form-field [formGroup]="subTypeFormGroup" class="mat-block"> |
19 | <mat-label *ngIf="showLabel">{{ entitySubtypeTitle | translate }}</mat-label> | 19 | <mat-label *ngIf="showLabel">{{ entitySubtypeTitle | translate }}</mat-label> |
20 | - <mat-select [fxShow]="subTypesLoaded" | ||
21 | - class="tb-entity-subtype-select" matInput formControlName="subType"> | 20 | + <mat-select [fxShow]="subTypesLoaded" class="tb-entity-subtype-select" matInput formControlName="subType"> |
22 | <mat-option *ngFor="let subType of subTypesOptions | async" [value]="subType"> | 21 | <mat-option *ngFor="let subType of subTypesOptions | async" [value]="subType"> |
23 | {{ displaySubTypeFn(subType) }} | 22 | {{ displaySubTypeFn(subType) }} |
24 | </mat-option> | 23 | </mat-option> |
@@ -211,13 +211,13 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni | @@ -211,13 +211,13 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni | ||
211 | if (!this.subTypes) { | 211 | if (!this.subTypes) { |
212 | switch (this.entityType) { | 212 | switch (this.entityType) { |
213 | case EntityType.ASSET: | 213 | case EntityType.ASSET: |
214 | - this.subTypes = this.assetService.getAssetTypes(false, true); | 214 | + this.subTypes = this.assetService.getAssetTypes({ignoreLoading: true}); |
215 | break; | 215 | break; |
216 | case EntityType.DEVICE: | 216 | case EntityType.DEVICE: |
217 | - this.subTypes = this.deviceService.getDeviceTypes(false, true); | 217 | + this.subTypes = this.deviceService.getDeviceTypes({ignoreLoading: true}); |
218 | break; | 218 | break; |
219 | case EntityType.ENTITY_VIEW: | 219 | case EntityType.ENTITY_VIEW: |
220 | - this.subTypes = this.entityViewService.getEntityViewTypes(false, true); | 220 | + this.subTypes = this.entityViewService.getEntityViewTypes({ignoreLoading: true}); |
221 | break; | 221 | break; |
222 | } | 222 | } |
223 | if (this.subTypes) { | 223 | if (this.subTypes) { |
@@ -227,6 +227,20 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni | @@ -227,6 +227,20 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni | ||
227 | this.subTypesLoaded = true; | 227 | this.subTypesLoaded = true; |
228 | return allSubtypes; | 228 | return allSubtypes; |
229 | }), | 229 | }), |
230 | + tap((subTypes) => { | ||
231 | + const type: EntitySubtype | string = this.subTypeFormGroup.get('subType').value; | ||
232 | + const strType = typeof type === 'string' ? type : type.type; | ||
233 | + const found = subTypes.find((subType) => { | ||
234 | + if (typeof subType === 'string') { | ||
235 | + return subType === type; | ||
236 | + } else { | ||
237 | + return subType.type === strType; | ||
238 | + } | ||
239 | + }); | ||
240 | + if (found) { | ||
241 | + this.subTypeFormGroup.get('subType').patchValue(found); | ||
242 | + } | ||
243 | + }), | ||
230 | publishReplay(1), | 244 | publishReplay(1), |
231 | refCount() | 245 | refCount() |
232 | ); | 246 | ); |
@@ -107,7 +107,9 @@ export class FullscreenDirective implements OnChanges, OnDestroy { | @@ -107,7 +107,9 @@ export class FullscreenDirective implements OnChanges, OnDestroy { | ||
107 | if (this.elementRef) { | 107 | if (this.elementRef) { |
108 | this.elementRef.nativeElement.classList.remove('tb-fullscreen'); | 108 | this.elementRef.nativeElement.classList.remove('tb-fullscreen'); |
109 | } | 109 | } |
110 | - this.overlayRef.dispose(); | 110 | + if (this.overlayRef) { |
111 | + this.overlayRef.dispose(); | ||
112 | + } | ||
111 | this.fullscreenChanged.emit(false); | 113 | this.fullscreenChanged.emit(false); |
112 | } | 114 | } |
113 | } | 115 | } |
@@ -22,8 +22,8 @@ import {DeviceCredentialsId} from '@shared/models/id/device-credentials-id'; | @@ -22,8 +22,8 @@ import {DeviceCredentialsId} from '@shared/models/id/device-credentials-id'; | ||
22 | import { EntitySearchQuery } from '@shared/models/relation.models'; | 22 | import { EntitySearchQuery } from '@shared/models/relation.models'; |
23 | 23 | ||
24 | export interface Asset extends BaseData<AssetId> { | 24 | export interface Asset extends BaseData<AssetId> { |
25 | - tenantId: TenantId; | ||
26 | - customerId: CustomerId; | 25 | + tenantId?: TenantId; |
26 | + customerId?: CustomerId; | ||
27 | name: string; | 27 | name: string; |
28 | type: string; | 28 | type: string; |
29 | additionalInfo?: any; | 29 | additionalInfo?: any; |
@@ -63,6 +63,7 @@ export const HelpLinks = { | @@ -63,6 +63,7 @@ export const HelpLinks = { | ||
63 | devices: helpBaseUrl + '/docs/user-guide/ui/devices', | 63 | devices: helpBaseUrl + '/docs/user-guide/ui/devices', |
64 | assets: helpBaseUrl + '/docs/user-guide/ui/assets', | 64 | assets: helpBaseUrl + '/docs/user-guide/ui/assets', |
65 | entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views', | 65 | entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views', |
66 | + entitiesImport: helpBaseUrl + '/docs/user-guide/bulk-provisioning', | ||
66 | rulechains: helpBaseUrl + '/docs/user-guide/ui/rule-chains', | 67 | rulechains: helpBaseUrl + '/docs/user-guide/ui/rule-chains', |
67 | dashboards: helpBaseUrl + '/docs/user-guide/ui/dashboards', | 68 | dashboards: helpBaseUrl + '/docs/user-guide/ui/dashboards', |
68 | widgetsBundles: helpBaseUrl + '/docs/user-guide/ui/widget-library#bundles', | 69 | widgetsBundles: helpBaseUrl + '/docs/user-guide/ui/widget-library#bundles', |
@@ -98,7 +98,6 @@ export interface DashboardConfiguration { | @@ -98,7 +98,6 @@ export interface DashboardConfiguration { | ||
98 | states?: {[id: string]: DashboardState }; | 98 | states?: {[id: string]: DashboardState }; |
99 | entityAliases?: EntityAliases; | 99 | entityAliases?: EntityAliases; |
100 | [key: string]: any; | 100 | [key: string]: any; |
101 | - // TODO: | ||
102 | } | 101 | } |
103 | 102 | ||
104 | export interface Dashboard extends DashboardInfo { | 103 | export interface Dashboard extends DashboardInfo { |
@@ -22,11 +22,11 @@ import {DeviceCredentialsId} from '@shared/models/id/device-credentials-id'; | @@ -22,11 +22,11 @@ import {DeviceCredentialsId} from '@shared/models/id/device-credentials-id'; | ||
22 | import { EntitySearchQuery } from '@shared/models/relation.models'; | 22 | import { EntitySearchQuery } from '@shared/models/relation.models'; |
23 | 23 | ||
24 | export interface Device extends BaseData<DeviceId> { | 24 | export interface Device extends BaseData<DeviceId> { |
25 | - tenantId: TenantId; | ||
26 | - customerId: CustomerId; | 25 | + tenantId?: TenantId; |
26 | + customerId?: CustomerId; | ||
27 | name: string; | 27 | name: string; |
28 | type: string; | 28 | type: string; |
29 | - label: string; | 29 | + label?: string; |
30 | additionalInfo?: any; | 30 | additionalInfo?: any; |
31 | } | 31 | } |
32 | 32 |
@@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
17 | import { BaseData } from '@shared/models/base-data'; | 17 | import { BaseData } from '@shared/models/base-data'; |
18 | import { EntityType } from '@shared/models/entity-type.models'; | 18 | import { EntityType } from '@shared/models/entity-type.models'; |
19 | import { EntityId } from '@shared/models/id/entity-id'; | 19 | import { EntityId } from '@shared/models/id/entity-id'; |
20 | +import { AttributeData } from './telemetry/telemetry.models'; | ||
20 | 21 | ||
21 | export interface EntityInfo { | 22 | export interface EntityInfo { |
22 | origEntity?: BaseData<EntityId>; | 23 | origEntity?: BaseData<EntityId>; |
@@ -26,3 +27,26 @@ export interface EntityInfo { | @@ -26,3 +27,26 @@ export interface EntityInfo { | ||
26 | id?: string; | 27 | id?: string; |
27 | entityDescription?: string; | 28 | entityDescription?: string; |
28 | } | 29 | } |
30 | + | ||
31 | +export interface ImportEntityData { | ||
32 | + name: string; | ||
33 | + type: string; | ||
34 | + accessToken: string; | ||
35 | + attributes: { | ||
36 | + server: AttributeData[], | ||
37 | + shared: AttributeData[] | ||
38 | + }; | ||
39 | + timeseries: AttributeData[]; | ||
40 | +} | ||
41 | + | ||
42 | +export interface ImportEntitiesResultInfo { | ||
43 | + create?: { | ||
44 | + entity: number; | ||
45 | + }; | ||
46 | + update?: { | ||
47 | + entity: number; | ||
48 | + }; | ||
49 | + error?: { | ||
50 | + entity: number; | ||
51 | + }; | ||
52 | +} |
@@ -14,17 +14,16 @@ | @@ -14,17 +14,16 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -export class LoginRequest { | 17 | +export interface LoginRequest { |
18 | username: string; | 18 | username: string; |
19 | password: string; | 19 | password: string; |
20 | +} | ||
20 | 21 | ||
21 | - constructor(username: string, password: string) { | ||
22 | - this.username = username; | ||
23 | - this.password = password; | ||
24 | - } | 22 | +export interface PublicLoginRequest { |
23 | + publicId: string; | ||
25 | } | 24 | } |
26 | 25 | ||
27 | -export class LoginResponse { | 26 | +export interface LoginResponse { |
28 | token: string; | 27 | token: string; |
29 | refreshToken: string; | 28 | refreshToken: string; |
30 | } | 29 | } |
@@ -50,3 +50,8 @@ export interface UserPasswordPolicy { | @@ -50,3 +50,8 @@ export interface UserPasswordPolicy { | ||
50 | export interface SecuritySettings { | 50 | export interface SecuritySettings { |
51 | passwordPolicy: UserPasswordPolicy; | 51 | passwordPolicy: UserPasswordPolicy; |
52 | } | 52 | } |
53 | + | ||
54 | +export interface UpdateMessage { | ||
55 | + message: string; | ||
56 | + updateAvailable: boolean; | ||
57 | +} |
@@ -20,6 +20,7 @@ import { AggregationType } from '../time/time.models'; | @@ -20,6 +20,7 @@ import { AggregationType } from '../time/time.models'; | ||
20 | import { Observable, ReplaySubject, Subject } from 'rxjs'; | 20 | import { Observable, ReplaySubject, Subject } from 'rxjs'; |
21 | import { EntityId } from '@shared/models/id/entity-id'; | 21 | import { EntityId } from '@shared/models/id/entity-id'; |
22 | import { map } from 'rxjs/operators'; | 22 | import { map } from 'rxjs/operators'; |
23 | +import { NgZone } from '@angular/core'; | ||
23 | 24 | ||
24 | export enum DataKeyType { | 25 | export enum DataKeyType { |
25 | timeseries = 'timeseries', | 26 | timeseries = 'timeseries', |
@@ -64,7 +65,7 @@ export const isClientSideTelemetryType = new Map<TelemetryType, boolean>( | @@ -64,7 +65,7 @@ export const isClientSideTelemetryType = new Map<TelemetryType, boolean>( | ||
64 | ); | 65 | ); |
65 | 66 | ||
66 | export interface AttributeData { | 67 | export interface AttributeData { |
67 | - lastUpdateTs: number; | 68 | + lastUpdateTs?: number; |
68 | key: string; | 69 | key: string; |
69 | value: any; | 70 | value: any; |
70 | } | 71 | } |
@@ -231,6 +232,8 @@ export class TelemetrySubscriber { | @@ -231,6 +232,8 @@ export class TelemetrySubscriber { | ||
231 | private dataSubject = new ReplaySubject<SubscriptionUpdate>(); | 232 | private dataSubject = new ReplaySubject<SubscriptionUpdate>(); |
232 | private reconnectSubject = new Subject(); | 233 | private reconnectSubject = new Subject(); |
233 | 234 | ||
235 | + private zone: NgZone; | ||
236 | + | ||
234 | public subscriptionCommands: Array<TelemetryPluginCmd>; | 237 | public subscriptionCommands: Array<TelemetryPluginCmd>; |
235 | 238 | ||
236 | public data$ = this.dataSubject.asObservable(); | 239 | public data$ = this.dataSubject.asObservable(); |
@@ -238,7 +241,7 @@ export class TelemetrySubscriber { | @@ -238,7 +241,7 @@ export class TelemetrySubscriber { | ||
238 | 241 | ||
239 | public static createEntityAttributesSubscription(telemetryService: TelemetryService, | 242 | public static createEntityAttributesSubscription(telemetryService: TelemetryService, |
240 | entityId: EntityId, attributeScope: TelemetryType, | 243 | entityId: EntityId, attributeScope: TelemetryType, |
241 | - keys: string[] = null): TelemetrySubscriber { | 244 | + zone: NgZone, keys: string[] = null): TelemetrySubscriber { |
242 | let subscriptionCommand: SubscriptionCmd; | 245 | let subscriptionCommand: SubscriptionCmd; |
243 | if (attributeScope === LatestTelemetry.LATEST_TELEMETRY) { | 246 | if (attributeScope === LatestTelemetry.LATEST_TELEMETRY) { |
244 | subscriptionCommand = new TimeseriesSubscriptionCmd(); | 247 | subscriptionCommand = new TimeseriesSubscriptionCmd(); |
@@ -252,6 +255,7 @@ export class TelemetrySubscriber { | @@ -252,6 +255,7 @@ export class TelemetrySubscriber { | ||
252 | subscriptionCommand.keys = keys.join(','); | 255 | subscriptionCommand.keys = keys.join(','); |
253 | } | 256 | } |
254 | const subscriber = new TelemetrySubscriber(telemetryService); | 257 | const subscriber = new TelemetrySubscriber(telemetryService); |
258 | + subscriber.zone = zone; | ||
255 | subscriber.subscriptionCommands.push(subscriptionCommand); | 259 | subscriber.subscriptionCommands.push(subscriptionCommand); |
256 | return subscriber; | 260 | return subscriber; |
257 | } | 261 | } |
@@ -280,7 +284,15 @@ export class TelemetrySubscriber { | @@ -280,7 +284,15 @@ export class TelemetrySubscriber { | ||
280 | } | 284 | } |
281 | } | 285 | } |
282 | message.prepareData(keys); | 286 | message.prepareData(keys); |
283 | - this.dataSubject.next(message); | 287 | + if (this.zone) { |
288 | + this.zone.run( | ||
289 | + () => { | ||
290 | + this.dataSubject.next(message); | ||
291 | + } | ||
292 | + ); | ||
293 | + } else { | ||
294 | + this.dataSubject.next(message); | ||
295 | + } | ||
284 | } | 296 | } |
285 | 297 | ||
286 | public onReconnected() { | 298 | public onReconnected() { |
@@ -262,7 +262,6 @@ export interface Datasource { | @@ -262,7 +262,6 @@ export interface Datasource { | ||
262 | entityDescription?: string; | 262 | entityDescription?: string; |
263 | generated?: boolean; | 263 | generated?: boolean; |
264 | [key: string]: any; | 264 | [key: string]: any; |
265 | - // TODO: | ||
266 | } | 265 | } |
267 | 266 | ||
268 | export type DataSet = [number, any][]; | 267 | export type DataSet = [number, any][]; |
@@ -61,6 +61,7 @@ import { RouterModule } from '@angular/router'; | @@ -61,6 +61,7 @@ import { RouterModule } from '@angular/router'; | ||
61 | import { ShareModule as ShareButtonsModule } from '@ngx-share/core'; | 61 | import { ShareModule as ShareButtonsModule } from '@ngx-share/core'; |
62 | import { HotkeyModule } from 'angular2-hotkeys'; | 62 | import { HotkeyModule } from 'angular2-hotkeys'; |
63 | import { ColorPickerModule } from 'ngx-color-picker'; | 63 | import { ColorPickerModule } from 'ngx-color-picker'; |
64 | +import { NgxHmCarouselModule } from 'ngx-hm-carousel'; | ||
64 | import { UserMenuComponent } from '@shared/components/user-menu.component'; | 65 | import { UserMenuComponent } from '@shared/components/user-menu.component'; |
65 | import { NospacePipe } from './pipe/nospace.pipe'; | 66 | import { NospacePipe } from './pipe/nospace.pipe'; |
66 | import { TranslateModule } from '@ngx-translate/core'; | 67 | import { TranslateModule } from '@ngx-translate/core'; |
@@ -233,6 +234,7 @@ import { FileInputComponent } from './components/file-input.component'; | @@ -233,6 +234,7 @@ import { FileInputComponent } from './components/file-input.component'; | ||
233 | ShareButtonsModule, | 234 | ShareButtonsModule, |
234 | HotkeyModule, | 235 | HotkeyModule, |
235 | ColorPickerModule, | 236 | ColorPickerModule, |
237 | + NgxHmCarouselModule, | ||
236 | NgxFlowModule | 238 | NgxFlowModule |
237 | ], | 239 | ], |
238 | exports: [ | 240 | exports: [ |
@@ -314,6 +316,7 @@ import { FileInputComponent } from './components/file-input.component'; | @@ -314,6 +316,7 @@ import { FileInputComponent } from './components/file-input.component'; | ||
314 | ShareButtonsModule, | 316 | ShareButtonsModule, |
315 | HotkeyModule, | 317 | HotkeyModule, |
316 | ColorPickerModule, | 318 | ColorPickerModule, |
319 | + NgxHmCarouselModule, | ||
317 | ColorPickerDialogComponent, | 320 | ColorPickerDialogComponent, |
318 | MaterialIconsDialogComponent, | 321 | MaterialIconsDialogComponent, |
319 | ColorInputComponent, | 322 | ColorInputComponent, |
@@ -52,7 +52,8 @@ | @@ -52,7 +52,8 @@ | ||
52 | "import": "Import", | 52 | "import": "Import", |
53 | "export": "Export", | 53 | "export": "Export", |
54 | "share-via": "Share via {{provider}}", | 54 | "share-via": "Share via {{provider}}", |
55 | - "continue": "Continue" | 55 | + "continue": "Continue", |
56 | + "back": "Back" | ||
56 | }, | 57 | }, |
57 | "aggregation": { | 58 | "aggregation": { |
58 | "aggregation": "Aggregation", | 59 | "aggregation": "Aggregation", |