This is an automated email from the ASF dual-hosted git repository.

ababiichuk pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new b6b1361  AMBARI-23662 Log Search UI: subscription error on route 
changing
b6b1361 is described below

commit b6b13615d0de44bb08fba2cab21836844edc036f
Author: Istvan Tobias <[email protected]>
AuthorDate: Wed Apr 25 18:15:01 2018 +0200

    AMBARI-23662 Log Search UI: subscription error on route changing
---
 .../src/app/app-routing.module.ts                  |  4 +--
 .../components/breadrumbs/breadcrumbs.component.ts | 19 +++++++++++-
 .../cluster-filter/cluster-filter.component.ts     | 18 ++++++++---
 .../logs-container/logs-container.component.ts     | 18 ++++++-----
 .../components/search-box/search-box.component.ts  | 26 +++++++++++-----
 .../src/app/modules/shared/shared.module.ts        |  3 +-
 .../shipper-configuration.component.ts             | 13 --------
 ...ipper-service-configuration-form.component.html | 10 +++---
 ...shipper-service-configuration-form.component.ts | 36 ++++++++++++++++------
 .../shipper/directives/validator.directive.ts      |  3 +-
 .../app/modules/shipper/services/shipper.guard.ts  | 36 ++++++++++++++++++----
 .../app/modules/shipper/shipper-routing.module.ts  |  5 ++-
 .../src/app/services/auth.service.ts               | 10 +++---
 .../app/services/logs-filtering-utils.service.ts   |  2 +-
 .../src/app/services/tab.guard.ts                  |  5 +--
 .../ambari-logsearch-web/src/assets/i18n/en.json   |  4 +++
 16 files changed, 141 insertions(+), 71 deletions(-)

diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/app-routing.module.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/app-routing.module.ts
index ed8cfb7..5fb281b 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/app-routing.module.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/app-routing.module.ts
@@ -45,8 +45,8 @@ const appRoutes: Routes = [{
     path: 'logs',
     component: LogsContainerComponent,
     data: {
-      multiClusterFilter: true,
-      breadcrumbs: 'logs.title'
+      breadcrumbs: 'logs.title',
+      multiClusterFilter: true
     },
     canActivate: [AuthGuardService, TabGuard]
   }, {
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/breadrumbs/breadcrumbs.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/breadrumbs/breadcrumbs.component.ts
index 99e394c..839a02c 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/breadrumbs/breadcrumbs.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/breadrumbs/breadcrumbs.component.ts
@@ -18,6 +18,9 @@
 import {Component, Input, OnDestroy, OnInit} from '@angular/core';
 import {Subscription} from 'rxjs/Subscription';
 import {ActivatedRouteSnapshot, NavigationEnd, Router, RoutesRecognized} from 
'@angular/router';
+import {Title} from '@angular/platform-browser';
+import {TranslateService} from '@ngx-translate/core';
+import {Observable} from 'rxjs/Observable';
 
 export interface BreadCrumb {
   text: string;
@@ -38,7 +41,11 @@ export class BreadcrumbsComponent implements OnInit, 
OnDestroy {
   @Input()
   addRootFirst: boolean = true;
 
-  constructor(private router: Router) { }
+  constructor(
+    private router: Router,
+    private titleService: Title,
+    private translateService: TranslateService
+  ) { }
 
   ngOnInit() {
     this.subscriptions.push(
@@ -76,8 +83,18 @@ export class BreadcrumbsComponent implements OnInit, 
OnDestroy {
     return breadcrumbs;
   }
 
+  setPageTite(pageTitle) {
+    Observable.combineLatest(
+      this.translateService.get('common.title'),
+      pageTitle ? this.translateService.get(pageTitle) : Observable.of('')
+    ).first().subscribe(([commonTitle, pageTite]) => {
+      this.titleService.setTitle(pageTitle ? `${commonTitle} - ${pageTite}` : 
commonTitle);
+    });
+  }
+
   onNavigationEnd = (): void => {
     this.crumbs = 
this.getCrumbsFromRouterStateSnapshot(this.router.routerState.snapshot.root);
+    this.setPageTite(this.crumbs[this.crumbs.length - 1].text);
   }
 
 }
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
index d9b64a1..de766a0 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
@@ -27,6 +27,8 @@ import {ClusterSelectionService} from 
'@app/services/storage/cluster-selection.s
 import {BehaviorSubject} from 'rxjs/BehaviorSubject';
 import {FilterDropdownComponent} from 
'@modules/shared/components/filter-dropdown/filter-dropdown.component';
 import {RoutingUtilsService} from '@app/services/routing-utils.service';
+import {AppStateService} from '@app/services/storage/app-state.service';
+import {DataAvailabilityValues} from '@app/classes/string';
 
 @Component({
   selector: 'cluster-filter',
@@ -53,7 +55,8 @@ export class ClusterFilterComponent implements OnInit, 
OnDestroy {
     private utilsService: UtilsService,
     private router: Router,
     private clusterSelectionStoreService: ClusterSelectionService,
-    private routingUtilsService: RoutingUtilsService
+    private routingUtilsService: RoutingUtilsService,
+    private appStateService: AppStateService
   ) { }
 
   ngOnInit() {
@@ -98,10 +101,15 @@ export class ClusterFilterComponent implements OnInit, 
OnDestroy {
   private setDropdownSelectionByActivatedRouteSnapshot(routeSnapshot: 
ActivatedRouteSnapshot): void {
     let clusterSelection = 
this.routingUtilsService.getParamFromActivatedRouteSnapshot(routeSnapshot, 
'cluster');
     if (clusterSelection) {
-      clusterSelection = this.useMultiSelection.getValue() ? 
clusterSelection.split(/,|;/) : clusterSelection;
-      
this.filterDropdown.updateSelection(Object.assign(this.utilsService.getListItemFromString(clusterSelection),
 {
-        isChecked: true
-      }));
+      clusterSelection = this.useMultiSelection.getValue() ? 
clusterSelection.split(/[,;]/) : clusterSelection;
+      this.appStateService.getParameter('clustersDataState')
+        .filter((state: DataAvailabilityValues) => state === 
DataAvailabilityValues.AVAILABLE)
+        .first()
+        .subscribe(() => {
+          
this.filterDropdown.updateSelection(Object.assign(this.utilsService.getListItemFromString(clusterSelection),
 {
+            isChecked: true
+          }));
+        });
     }
   }
 
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
index 0d808fc..37c6492 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
@@ -138,25 +138,27 @@ export class LogsContainerComponent implements OnInit, 
OnDestroy {
     this.subscriptions.push(
       this.activatedRoute.queryParams.filter(() => 
!this.queryParamsSyncInProgress.getValue()).subscribe(this.onQueryParamsChange)
     );
-    if (!this.activatedRoute.queryParams || 
!Object.keys(this.activatedRoute.queryParams).length) {
-      this.syncFiltersToQueryParams(this.filtersForm.value);
-    }
+    this.activatedRoute.queryParams.first().subscribe((params) => {
+      if (!Object.keys(params).length) {
+        this.syncFiltersToQueryParams(this.filtersForm.value);
+      }
+    });
 
     this.subscriptions.push(
       
this.logsStateService.getParameter('activeTabId').skip(1).subscribe(this.onActiveTabSwitched)
     );
 
+    this.subscriptions.push(
+      Observable.fromEvent(window, 'scroll').throttleTime(10).subscribe(() => {
+        this.setFixedPositionValue();
+      })
+    );
   }
 
   ngOnDestroy() {
     this.subscriptions.forEach((subscription: Subscription) => 
subscription.unsubscribe());
   }
 
-  @HostListener('window:scroll', ['$event'])
-  onWindowScroll(): void {
-    this.setFixedPositionValue();
-  }
-
   get filtersForm(): FormGroup {
     return this.logsContainerService.filtersForm;
   };
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts
index b9a43df..eb48bf7 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts
@@ -23,6 +23,7 @@ import {SearchBoxParameter, SearchBoxParameterProcessed, 
SearchBoxParameterTrigg
 import {ListItem} from '@app/classes/list-item';
 import {HomogeneousObject} from '@app/classes/object';
 import {UtilsService} from '@app/services/utils.service';
+import {Subscription} from 'rxjs/Subscription';
 
 @Component({
   selector: 'search-box',
@@ -120,20 +121,29 @@ export class SearchBoxComponent implements OnInit, 
OnDestroy, ControlValueAccess
    */
   parameters: SearchBoxParameterProcessed[] = [];
 
+  private subscriptions: Subscription[] = [];
+
   constructor(private utils: UtilsService) {}
 
   ngOnInit(): void {
     this.parameterInput = this.parameterInputRef.nativeElement;
     this.valueInput = this.valueInputRef.nativeElement;
-    this.parameterNameChangeSubject.subscribe(this.onParameterNameChange);
-    this.parameterAddSubject.subscribe(this.onParameterAdd);
-    this.updateValueSubject.subscribe(this.updateValue);
+    this.subscriptions.push(
+      this.parameterNameChangeSubject.subscribe(this.onParameterNameChange)
+    );
+    this.subscriptions.push(
+      this.parameterAddSubject.subscribe(this.onParameterAdd)
+    );
+    this.subscriptions.push(
+      this.updateValueSubject.subscribe(this.updateValue)
+    );
   }
 
   ngOnDestroy(): void {
-    this.parameterNameChangeSubject.unsubscribe();
-    this.parameterAddSubject.unsubscribe();
-    this.updateValueSubject.unsubscribe();
+    // this.parameterNameChangeSubject.unsubscribe();
+    // this.parameterAddSubject.unsubscribe();
+    // this.updateValueSubject.unsubscribe();
+    this.subscriptions.forEach((subscription: Subscription) => 
subscription.unsubscribe());
   }
 
   /**
@@ -175,7 +185,7 @@ export class SearchBoxComponent implements OnInit, 
OnDestroy, ControlValueAccess
     this.isActive = true;
     this.isValueInput = false;
     setTimeout(() => this.parameterInput.focus(), 0);
-  };
+  }
 
   private getItemByValue(name: string): ListItem {
     return this.items.find((field: ListItem): boolean => field.value === name);
@@ -208,7 +218,7 @@ export class SearchBoxComponent implements OnInit, 
OnDestroy, ControlValueAccess
     this.isValueInput = true;
     this.currentValue = '';
     this.valueInput.focus();
-  };
+  }
 
   onParameterValueKeyDown(event: KeyboardEvent): void {
     if (this.utils.isBackSpacePressed(event) && !this.currentValue) {
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
index 2f5a9ae..5a6c8d9 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
@@ -18,7 +18,7 @@
 
 import {NgModule} from '@angular/core';
 import {CommonModule} from '@angular/common';
-import {BrowserModule} from '@angular/platform-browser';
+import {BrowserModule, Title} from '@angular/platform-browser';
 import {FormsModule} from '@angular/forms';
 import {Http} from '@angular/http';
 import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@@ -59,6 +59,7 @@ import {ModalComponent} from 
'./components/modal/modal.component';
     ModalComponent
   ],
   providers: [
+    Title,
     NotificationService,
     CanDeactivateGuardService,
     Angular2NotificationsService
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts
index 33466a1..8c43a97 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts
@@ -82,19 +82,6 @@ export class ShipperConfigurationComponent implements 
CanComponentDeactivate, On
   ) { }
 
   ngOnInit() {
-    // check if we have cluster name parameter.
-    this.clusterName$.first().subscribe((clusterName: ShipperCluster) => {
-      if (!clusterName) { // if not let's redirect to the first cluster
-        this.clustersStoreService.getAll()
-          .skipWhile((clusterList: ShipperCluster[]) => {
-            return !clusterList || !clusterList.length;
-          })
-          .map((clusterList: ShipperCluster[]) => clusterList[0])
-          .switchMap((cluster: ShipperCluster) => 
this.getPathMapForClusterFirstService(cluster))
-          .first()
-          .subscribe((path: string[]) => this.router.navigate(path));
-      }
-    });
     this.subscriptions.push(
       this.clusterSelectionStoreService
         .getParameter(ShipperConfigurationComponent.clusterSelectionStoreKey)
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html
 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html
index 765aa50..9ab7194 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html
@@ -68,14 +68,14 @@
           <form [formGroup]="validatorForm" 
(ngSubmit)="onValidationSubmit($event)">
             <h2>{{'shipperConfiguration.validator.title' | translate}}</h2>
             <input type="hidden" name="clusterName" 
formControlName="clusterName">
-            <div [ngClass]="{'has-warning': componentNameField.invalid, 
'form-group': true}">
+            <div class="form-group" 
[class.has-warning]="componentNameField.invalid">
               <label>
                 {{'shipperConfiguration.validator.componentNameLabel' | 
translate}}
-                <span *ngIf="componentNameField.errors && 
componentNameField.errors.required"
+                <span [class.hide]="!componentNameField.errors || 
!componentNameField.errors.required"
                       class="help-block validation-block pull-right">
                   {{'common.form.errors.required' | translate}}
                 </span>
-                <span *ngIf="validatorForm.controls.componentName.value && 
componentNameField.errors && 
componentNameField.errors.serviceNameDoesNotExistInConfiguration"
+                <span [class.hide]="!componentNameField.value || 
!componentNameField.errors || 
!componentNameField.errors.serviceNameDoesNotExistInConfiguration"
                       class="help-block validation-block pull-right">
                   
{{'shipperConfiguration.form.errors.componentNameField.serviceNameDoesNotExistInConfiguration'
 | translate}}
                 </span>
@@ -86,10 +86,10 @@
                      [typeaheadMinLength]="0"
                      [disableControl]="configurationForm.invalid">
             </div>
-            <div [ngClass]="{'has-warning': sampleDataField.invalid, 
'form-group': true}">
+            <div class="form-group" 
[class.has-warning]="sampleDataField.invalid">
               <label>
                 {{'shipperConfiguration.validator.sampleDataLabel' | 
translate}}
-                <span *ngIf="sampleDataField.errors && 
sampleDataField.errors.required"
+                <span [class.hide]="!sampleDataField.errors || 
!sampleDataField.errors.required"
                       class="help-block validation-block pull-right">
                   {{'common.form.errors.required' | translate}}
                 </span>
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts
index b28c0d9..2089306 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-import {Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, 
SimpleChanges} from '@angular/core';
+import {ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, 
OnDestroy, OnInit, Output, SimpleChanges} from '@angular/core';
 import {AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators} from 
'@angular/forms';
 import {Observable} from 'rxjs/Observable';
 import {Subject} from 'rxjs/Subject';
@@ -35,6 +35,7 @@ import * as formValidators from 
'../../directives/validator.directive';
 import {BehaviorSubject} from 'rxjs/BehaviorSubject';
 import {Subscription} from 'rxjs/Subscription';
 import {ShipperClusterServiceValidationModel} from 
'@modules/shipper/models/shipper-cluster-service-validation.model';
+import {ActivatedRoute} from '@angular/router';
 
 @Component({
   selector: 'shipper-configuration-form',
@@ -107,11 +108,28 @@ export class ShipperServiceConfigurationFormComponent 
implements OnInit, OnDestr
 
   constructor(
     private utilsService: UtilsService,
-    private formBuilder: FormBuilder
-  ) {}
+    private formBuilder: FormBuilder,
+    private activatedRoute: ActivatedRoute,
+    private changeDetectionRef: ChangeDetectorRef
+  ) {
+    // This is a fix to avoid the ExpressionChangedAfterItHasBeenCheckedError 
exception
+    // We create forms checking if there is serviceName set, so that is why we 
put this in the constructor.
+    this.createForms();
+  }
 
   ngOnInit() {
-    this.createForms();
+    this.subscriptions.push(
+      this.activatedRoute.params.map(params => 
params.service).subscribe((service) => {
+        this.serviceName = service;
+      })
+    );
+    if (!this.serviceName) {
+      this.configurationForm.controls.serviceName.setValidators([
+        Validators.required,
+        formValidators.uniqueServiceNameValidator(this.serviceNamesListSubject)
+      ]);
+      this.changeDetectionRef.detectChanges();
+    }
     this.configurationComponents$ = 
this.configurationForm.controls.configuration.valueChanges.map((newValue: 
string): string[] => {
       let components: string[];
       try {
@@ -163,6 +181,10 @@ export class ShipperServiceConfigurationFormComponent 
implements OnInit, OnDestr
     }
   }
 
+  onServiceParamsChange = (service): void => {
+
+  }
+
   leaveDirtyFormConfirmed = () => {
     this.canDeactivateModalResult.next(true);
     this.isLeavingDirtyForm = false;
@@ -189,15 +211,11 @@ export class ShipperServiceConfigurationFormComponent 
implements OnInit, OnDestr
     const configuration: ShipperClusterServiceConfigurationInterface = 
this.configuration || (
       this.serviceName ? this.configuration : new ShipperConfigurationModel()
     );
-    const configurationFormValidators: ValidatorFn[] = [Validators.required];
-    if (!this.serviceName) {
-      
configurationFormValidators.push(formValidators.uniqueServiceNameValidator(this.serviceNamesListSubject));
-    }
     this.configurationForm = this.formBuilder.group({
       clusterName: this.formBuilder.control(this.clusterName, 
Validators.required),
       serviceName: this.formBuilder.control(
         this.serviceName,
-        configurationFormValidators
+        [Validators.required]
       ),
       configuration: this.formBuilder.control(
         this.getConfigurationAsString(configuration),
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts
index ad6f009..50c1237 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts
@@ -16,11 +16,10 @@
  * limitations under the License.
  */
 
-import {AbstractControl, AsyncValidatorFn, ValidatorFn} from '@angular/forms';
+import {AbstractControl, ValidatorFn} from '@angular/forms';
 import {ShipperClusterService} from 
'@modules/shipper/models/shipper-cluster-service.type';
 import {ValidationErrors} from '@angular/forms/src/directives/validators';
 import {BehaviorSubject} from 'rxjs/BehaviorSubject';
-import {Observable} from 'rxjs/Observable';
 
 export function configurationValidator(): ValidatorFn {
   return (control: AbstractControl): ValidationErrors | null => {
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/services/shipper.guard.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/services/shipper.guard.ts
index f57a6c7..a8e2320 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/services/shipper.guard.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/services/shipper.guard.ts
@@ -21,6 +21,8 @@ import {Observable} from 'rxjs/Observable';
 import {RoutingUtilsService} from '@app/services/routing-utils.service';
 import {ClustersService} from '@app/services/storage/clusters.service';
 import {ShipperClusterServiceListService} from 
'@modules/shipper/services/shipper-cluster-service-list.service';
+import {NotificationService, NotificationType} from 
'@modules/shared/services/notification.service';
+import {TranslateService} from '@ngx-translate/core';
 
 @Injectable()
 export class ShipperGuard implements CanActivate {
@@ -29,7 +31,9 @@ export class ShipperGuard implements CanActivate {
     private routingUtilsService: RoutingUtilsService,
     private router: Router,
     private clustersStoreService: ClustersService,
-    private shipperClusterServiceListService: ShipperClusterServiceListService
+    private shipperClusterServiceListService: ShipperClusterServiceListService,
+    private translateService: TranslateService,
+    private notificationService: NotificationService
   ) {}
 
   getFirstCluster(): Observable<string> {
@@ -47,11 +51,31 @@ export class ShipperGuard implements CanActivate {
   ): Observable<boolean> | Promise<boolean> | boolean {
     const cluster: string = 
this.routingUtilsService.getParamFromActivatedRouteSnapshot(next, 'cluster');
     const service: string = 
this.routingUtilsService.getParamFromActivatedRouteSnapshot(next, 'service');
-    (cluster ? Observable.of(cluster) : 
this.getFirstCluster()).first().subscribe((firstCluster: string) => {
-      
this.getFirstServiceForCluster(firstCluster).first().subscribe((firstService: 
string) => {
-        this.router.navigate(['/shipper', firstCluster, firstService]);
+    return this.clustersStoreService.getAll().filter(clusters => 
clusters.length).first()
+      .map((clusters: string[]) => {
+        return clusters.indexOf(cluster) === -1 ? clusters[0] : cluster;
+      }) // checking cluster
+      .switchMap((validCluster: string) => {
+        return 
this.shipperClusterServiceListService.getServicesForCluster(validCluster) // 
getting valid services for validCluster
+          .map((services: string[]) => {
+            const canActivate: boolean = cluster === validCluster && service 
&& ('add' === service || services.indexOf(service) > -1);
+            // redirect if the cluster changed or the service is not in the 
valid services and it is not add new service path
+            if (!canActivate) {
+              const title = 'shipperConfiguration.navigation.title';
+              const invalidKey: string = cluster === validCluster ? 
'invalidService' : 'invalidCluster';
+              const message = 
this.translateService.instant(`shipperConfiguration.navigation.${invalidKey}`, {
+                cluster,
+                service
+              });
+              this.notificationService.addNotification({
+                title,
+                message,
+                type: NotificationType.ERROR
+              });
+              this.router.navigate(['/shipper', validCluster, services[0]]);
+            }
+            return canActivate;
+          });
       });
-    });
-    return !!(cluster && service);
   }
 }
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/shipper-routing.module.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/shipper-routing.module.ts
index 85d0bb9..5c92de0 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/shipper-routing.module.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shipper/shipper-routing.module.ts
@@ -41,7 +41,7 @@ const shipperRoutes: Routes = [{
     breadcrumbs: ['shipperConfiguration.breadcrumbs.title', 
'shipperConfiguration.breadcrumbs.update'],
     multiClusterFilter: false
   },
-  canActivate: [AuthGuardService],
+  canActivate: [AuthGuardService, ShipperGuard],
   canDeactivate: [CanDeactivateGuardService]
 }, {
   path: 'shipper/:cluster',
@@ -69,5 +69,4 @@ const shipperRoutes: Routes = [{
     RouterModule
   ]
 })
-export class ShipperRoutingModule {
-}
+export class ShipperRoutingModule {}
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.ts
index 50586f6..f5fb4dc 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.ts
@@ -23,8 +23,8 @@ import {Observable} from 'rxjs/Observable';
 
 import {HttpClientService} from '@app/services/http-client.service';
 import {AppStateService} from '@app/services/storage/app-state.service';
-import {Router} from "@angular/router";
-import {Subscription} from "rxjs/Subscription";
+import {Router} from '@angular/router';
+import {Subscription} from 'rxjs/Subscription';
 
 export const IS_AUTHORIZED_APP_STATE_KEY: string = 'isAuthorized';
 export const IS_LOGIN_IN_PROGRESS_APP_STATE_KEY: string = 'isLoginInProgress';
@@ -42,7 +42,7 @@ export class AuthService {
    * authorization done.
    * @type string
    */
-  redirectUrl: string;
+  redirectUrl: string | string[];
 
   constructor(
     private httpClient: HttpClientService,
@@ -55,8 +55,8 @@ export class AuthService {
   }
 
   onAppStateIsAuthorizedChanged = (isAuthorized): void => {
-    if (isAuthorized) {
-      this.router.navigate([this.redirectUrl || '/']);
+    if (isAuthorized && this.redirectUrl) {
+      this.router.navigate(Array.isArray(this.redirectUrl) ? this.redirectUrl 
: [this.redirectUrl]);
       this.redirectUrl = '';
     }
   }
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts
index f88fe72..3b98b45 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts
@@ -450,7 +450,7 @@ export class LogsFilteringUtilsService {
                 type: queryParams.sortingType
               }
             }]
-          }
+          };
           break;
         case 'query' :
           newFilter = {
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/tab.guard.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/tab.guard.ts
index 9fb4dda..5caeb6e 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/tab.guard.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/tab.guard.ts
@@ -34,10 +34,11 @@ export class TabGuard implements CanActivate {
   canActivate(
     next: ActivatedRouteSnapshot,
     state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | 
boolean {
-    const activeTabParam: string = 
this.routingUtilsService.getParamFromActivatedRouteSnapshot(next, 'activeTab');
+    const activeTabParam: string = 
this.routingUtilsService.getParamFromActivatedRouteSnapshot(state.root, 
'activeTab');
     return this.tabsStorageService.getAll().switchMap((tabs: Tab[]) => {
       if (!activeTabParam && tabs && tabs.length) {
-        this.router.navigate(['/logs', tabs[0].id]);
+        const tabId = (tabs.find((currentTab) => currentTab.isActive) || 
tabs[0]).id;
+        this.router.navigate(['/logs', tabId]);
       }
       const canActivate: boolean = !!activeTabParam && !!tabs.find((tab: Tab) 
=> tab.id === activeTabParam);
       return Observable.of(canActivate);
diff --git a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json 
b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
index e70ab9b..e5c2096 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
+++ b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
@@ -245,6 +245,10 @@
   "shipperConfiguration.validator.filters": "Filters",
   "shipperConfiguration.validator.result": "Validation result",
 
+  "shipperConfiguration.navigation.title": "Shipper Configuration",
+  "shipperConfiguration.navigation.invalidCluster": "The selected cluster name 
is invalid: <strong>{{cluster}}</strong>",
+  "shipperConfiguration.navigation.invalidService": "The selected service 
(<strong>{{service}}</strong>) is not on the selected cluster 
(<strong>{{cluster}}</strong>).",
+
   "shipperConfiguration.action.add.title": "New Configuration",
   "shipperConfiguration.action.add.success.message": "New configuration has 
been added successfully.",
   "shipperConfiguration.action.add.error.message": "Error at adding new 
configuration.<div class='cluster-name'>Cluster: {{clusterName}}</div><div 
class='service-name'>Service: {{componentName}}</div>",

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to