You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by mr...@apache.org on 2017/11/27 23:29:30 UTC

[18/30] ambari git commit: Merge trunk with feature branch and fix some UT compilation issues (mradhakrishnan)

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
new file mode 100644
index 0000000..bd6d012
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import '../mixins';
+
+:host {
+  /deep/ filter-dropdown {
+    justify-content: flex-end;
+  }
+
+  .panel-body {
+    overflow: hidden;
+    width: 100%;
+  }
+
+  table {
+    width: 100%;
+  }
+
+  tr.log-date-row, tr.log-date-row:hover {
+    background: @list-header-background-color;
+    border: none transparent;
+    th {
+      border: none transparent;
+    }
+  }
+  tr.log-item-row td {
+    background: none transparent;
+  }
+
+  td {
+    &.log-action {
+      min-width: 3em;
+      /deep/ .btn, /deep/ .filter-label {
+        font-size: 1em;
+        height: auto;
+        line-height: 1em;
+        padding: 0;
+      }
+    }
+    &.log-time {
+      color: @grey-color;
+      min-width: 7em;
+      text-align: right;
+    }
+    &.log-level {
+      text-transform: uppercase;
+      min-width: 8em;
+      .log-colors;
+    }
+    &.log-type {
+      color: @link-color;
+    }
+    &.log-message, &.log-path {
+      width: 100%;
+    }
+  }
+
+  tr:hover td.log-action {
+    /deep/ .btn {
+      display: inline-block;
+    }
+  }
+
+  .table.table-hover > tbody > tr {
+    box-sizing: border-box;
+    border-width: 1px;
+    > td {
+      border-top: 0 none;
+    }
+    &:first-of-type {
+      border-top-color: transparent;
+    }
+    &:last-of-type {
+      border-bottom-color: transparent;
+    }
+  }
+
+  .context-menu {
+    position: fixed;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts
new file mode 100644
index 0000000..0c323f7
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts
@@ -0,0 +1,126 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {StoreModule} from '@ngrx/store';
+import {MomentModule} from 'angular2-moment';
+import {MomentTimezoneModule} from 'angular-moment-timezone';
+import {TranslationModules} from '@app/test-config.spec';
+import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
+import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
+import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
+import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
+import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
+import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {AppStateService, appState} from '@app/services/storage/app-state.service';
+import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
+import {ClustersService, clusters} from '@app/services/storage/clusters.service';
+import {ComponentsService, components} from '@app/services/storage/components.service';
+import {HostsService, hosts} from '@app/services/storage/hosts.service';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {UtilsService} from '@app/services/utils.service';
+import {HttpClientService} from '@app/services/http-client.service';
+import {ComponentGeneratorService} from '@app/services/component-generator.service';
+import {ComponentActionsService} from '@app/services/component-actions.service';
+import {AuthService} from '@app/services/auth.service';
+import {PaginationComponent} from '@app/components/pagination/pagination.component';
+import {DropdownListComponent} from '@app/components/dropdown-list/dropdown-list.component';
+
+import {ServiceLogsTableComponent} from './service-logs-table.component';
+
+describe('ServiceLogsTableComponent', () => {
+  let component: ServiceLogsTableComponent;
+  let fixture: ComponentFixture<ServiceLogsTableComponent>;
+  const httpClient = {
+    get: () => {
+      return {
+        subscribe: () => {
+        }
+      };
+    }
+  };
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [
+        ServiceLogsTableComponent,
+        PaginationComponent,
+        DropdownListComponent
+      ],
+      imports: [
+        FormsModule,
+        ReactiveFormsModule,
+        MomentModule,
+        MomentTimezoneModule,
+        ...TranslationModules,
+        StoreModule.provideStore({
+          auditLogs,
+          serviceLogs,
+          auditLogsFields,
+          serviceLogsFields,
+          serviceLogsHistogramData,
+          serviceLogsTruncated,
+          appState,
+          appSettings,
+          tabs,
+          clusters,
+          components,
+          hosts
+        })
+      ],
+      providers: [
+        LogsContainerService,
+        UtilsService,
+        {
+          provide: HttpClientService,
+          useValue: httpClient
+        },
+        AuditLogsService,
+        ServiceLogsService,
+        AuditLogsFieldsService,
+        ServiceLogsFieldsService,
+        ServiceLogsHistogramDataService,
+        ServiceLogsTruncatedService,
+        AppStateService,
+        AppSettingsService,
+        TabsService,
+        ClustersService,
+        ComponentsService,
+        HostsService,
+        ComponentGeneratorService,
+        ComponentActionsService,
+        AuthService
+      ],
+      schemas: [CUSTOM_ELEMENTS_SCHEMA]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ServiceLogsTableComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create component', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
new file mode 100644
index 0000000..9f38371
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {Component, AfterViewInit, ViewChild, ElementRef} from '@angular/core';
+import {ListItem} from '@app/classes/list-item';
+import {LogsTableComponent} from '@app/classes/components/logs-table-component';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {UtilsService} from '@app/services/utils.service';
+
+@Component({
+  selector: 'service-logs-table',
+  templateUrl: './service-logs-table.component.html',
+  styleUrls: ['./service-logs-table.component.less']
+})
+export class ServiceLogsTableComponent extends LogsTableComponent implements AfterViewInit {
+
+  constructor(private logsContainer: LogsContainerService, private utils: UtilsService) {
+    super();
+  }
+
+  ngAfterViewInit() {
+    if (this.contextMenu) {
+      this.contextMenuElement = this.contextMenu.nativeElement;
+    }
+  }
+
+  @ViewChild('contextmenu', {
+    read: ElementRef
+  })
+  contextMenu: ElementRef;
+
+  readonly dateFormat: string = 'dddd, MMMM Do';
+
+  readonly timeFormat: string = 'h:mm:ss A';
+
+  readonly logActions = [
+    {
+      label: 'logs.copy',
+      iconClass: 'fa fa-files-o',
+      action: 'copyLog'
+    },
+    {
+      label: 'logs.open',
+      iconClass: 'fa fa-external-link',
+      action: 'openLog'
+    },
+    {
+      label: 'logs.context',
+      iconClass: 'fa fa-crosshairs',
+      action: 'openContext'
+    }
+  ];
+
+  readonly customStyledColumns: string[] = ['level', 'type', 'logtime', 'log_message'];
+
+  readonly contextMenuItems: ListItem[] = [
+    {
+      label: 'logs.addToQuery',
+      iconClass: 'fa fa-search-plus',
+      value: false // 'isExclude' is false
+    },
+    {
+      label: 'logs.excludeFromQuery',
+      iconClass: 'fa fa-search-minus',
+      value: true // 'isExclude' is true
+    }
+  ];
+
+  private readonly messageFilterParameterName: string = 'log_message';
+
+  private contextMenuElement: HTMLElement;
+
+  private selectedText: string = '';
+
+  get timeZone(): string {
+    return this.logsContainer.timeZone;
+  }
+
+  get filters(): any {
+    return this.logsContainer.filters;
+  }
+
+  get logsTypeMapObject(): object {
+    return this.logsContainer.logsTypeMap.serviceLogs;
+  }
+
+  isDifferentDates(dateA, dateB): boolean {
+    return this.utils.isDifferentDates(dateA, dateB, this.timeZone);
+  }
+
+  openMessageContextMenu(event: MouseEvent): void {
+    const selectedText = getSelection().toString();
+    if (selectedText) {
+      let contextMenuStyle = this.contextMenuElement.style;
+      Object.assign(contextMenuStyle, {
+        left: `${event.clientX}px`,
+        top: `${event.clientY}px`,
+        display: 'block'
+      });
+      this.selectedText = selectedText;
+      document.body.addEventListener('click', this.dismissContextMenu);
+      event.preventDefault();
+    }
+  }
+
+  updateQuery(event: ListItem): void {
+    this.logsContainer.queryParameterAdd.next({
+      name: this.messageFilterParameterName,
+      value: this.selectedText,
+      isExclude: event.value
+    });
+  }
+
+  private dismissContextMenu = (): void => {
+    this.selectedText = '';
+    this.contextMenuElement.style.display = 'none';
+    document.body.removeEventListener('click', this.dismissContextMenu);
+  };
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
index 973db61..c3f0b6a 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
@@ -16,13 +16,16 @@
 -->
 
 <button class="btn btn-link dropdown-toggle" data-toggle="dropdown">
-  {{selectedLabel | translate}} <span class="caret"></span>
+  <span *ngIf="selection">{{selection.label | translate}}</span>
+  <span class="caret"></span>
 </button>
 <div class="dropdown-menu row col-md-12">
   <div class="col-md-4" (click)="$event.stopPropagation()">
     <h4>{{'filter.timeRange' | translate}}</h4>
-    <date-picker (timeChange)="setStartTime($event)"></date-picker>
-    <date-picker (timeChange)="setEndTime($event)"></date-picker>
+    <div class="col-md-12 row text-uppercase">{{'filter.timeRange.from' | translate}}</div>
+    <date-picker class="col-md-12 row" [time]="startTime" (timeChange)="setStartTime($event)"></date-picker>
+    <div class="col-md-12 row text-uppercase">{{'filter.timeRange.to' | translate}}</div>
+    <date-picker class="col-md-12 row" [time]="endTime" (timeChange)="setEndTime($event)"></date-picker>
     <button class="btn btn-success pull-right" type="button" (click)="setCustomTimeRange()"
             [disabled]="!startTime || !endTime || startTime >= endTime">
       {{'modal.apply' | translate}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.spec.ts
index 7612cc3..43e4bd5 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.spec.ts
@@ -25,8 +25,15 @@ import {AppStateService, appState} from '@app/services/storage/app-state.service
 import {ClustersService, clusters} from '@app/services/storage/clusters.service';
 import {ComponentsService, components} from '@app/services/storage/components.service';
 import {HostsService, hosts} from '@app/services/storage/hosts.service';
+import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
+import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
+import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
+import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
+import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
+import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {HttpClientService} from '@app/services/http-client.service';
-import {FilteringService} from '@app/services/filtering.service';
+import {LogsContainerService} from '@app/services/logs-container.service';
 
 import {TimeRangePickerComponent} from './time-range-picker.component';
 
@@ -51,7 +58,14 @@ describe('TimeRangePickerComponent', () => {
           appState,
           clusters,
           components,
-          hosts
+          hosts,
+          auditLogs,
+          auditLogsFields,
+          serviceLogs,
+          serviceLogsFields,
+          serviceLogsHistogramData,
+          serviceLogsTruncated,
+          tabs
         }),
         ...TranslationModules
       ],
@@ -60,12 +74,19 @@ describe('TimeRangePickerComponent', () => {
           provide: HttpClientService,
           useValue: httpClient
         },
-        FilteringService,
+        LogsContainerService,
         AppSettingsService,
         AppStateService,
         ClustersService,
         ComponentsService,
-        HostsService
+        HostsService,
+        AuditLogsService,
+        AuditLogsFieldsService,
+        ServiceLogsService,
+        ServiceLogsFieldsService,
+        ServiceLogsHistogramDataService,
+        ServiceLogsTruncatedService,
+        TabsService
       ],
       schemas: [CUSTOM_ELEMENTS_SCHEMA]
     })

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
index af4933a..74a2b2d 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
@@ -16,10 +16,10 @@
  * limitations under the License.
  */
 
-import {Component, OnInit, Input, forwardRef} from '@angular/core';
+import {Component, forwardRef} from '@angular/core';
 import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
-import {Moment} from 'moment';
-import {FilteringService} from '@app/services/filtering.service';
+import {Moment} from 'moment-timezone';
+import {LogsContainerService} from '@app/services/logs-container.service';
 import {ListItem} from '@app/classes/list-item';
 import {TimeUnitListItem} from '@app/classes/filtering';
 
@@ -35,20 +35,11 @@ import {TimeUnitListItem} from '@app/classes/filtering';
     }
   ]
 })
-export class TimeRangePickerComponent implements OnInit, ControlValueAccessor {
+export class TimeRangePickerComponent implements ControlValueAccessor {
 
-  constructor(private filtering: FilteringService) {
+  constructor(private logsContainer: LogsContainerService) {
   }
 
-  ngOnInit() {
-    this.selectedLabel = this.defaultLabel;
-  }
-
-  @Input()
-  defaultLabel?: string;
-
-  selectedLabel: string;
-
   startTime: Moment;
 
   endTime: Moment;
@@ -56,18 +47,22 @@ export class TimeRangePickerComponent implements OnInit, ControlValueAccessor {
   private onChange: (fn: any) => void;
 
   get quickRanges(): (ListItem | TimeUnitListItem[])[] {
-    return this.filtering.filters.timeRange.options;
+    return this.logsContainer.filters.timeRange.options;
   }
 
-  private timeRange?: any;
+  private timeRange?: TimeUnitListItem;
 
-  get value(): any {
+  get selection(): TimeUnitListItem {
     return this.timeRange;
   }
 
-  set value(newValue: any) {
+  set selection(newValue: TimeUnitListItem) {
     this.timeRange = newValue;
-    this.onChange(newValue);
+    if (this.onChange) {
+      this.onChange(newValue);
+    }
+    this.setEndTime(this.logsContainer.getEndTimeMoment(newValue));
+    this.setStartTime(this.logsContainer.getStartTimeMoment(newValue, this.endTime));
   }
 
   setStartTime(timeObject: Moment): void {
@@ -78,28 +73,30 @@ export class TimeRangePickerComponent implements OnInit, ControlValueAccessor {
     this.endTime = timeObject;
   }
 
-  setTimeRange(value: any, label: string) {
-    this.value = value;
-    this.selectedLabel = label;
+  setTimeRange(value: any, label: string): void {
+    this.selection = {label, value};
   }
 
-  setCustomTimeRange() {
-    this.value = {
-      type: 'CUSTOM',
-      start: this.startTime,
-      end: this.endTime
+  setCustomTimeRange(): void {
+    this.selection = {
+      label: 'filter.timeRange.custom',
+      value: {
+        type: 'CUSTOM',
+        start: this.startTime,
+        end: this.endTime
+      }
     };
-    this.selectedLabel = 'filter.timeRange.custom';
   }
 
-  writeValue() {
+  writeValue(selection: TimeUnitListItem): void {
+    this.selection = selection;
   }
 
   registerOnChange(callback: any): void {
     this.onChange = callback;
   }
 
-  registerOnTouched() {
+  registerOnTouched(): void {
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
index 53afc47..ab56589 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
@@ -32,9 +32,9 @@ import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/se
 import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
 import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {ComponentActionsService} from '@app/services/component-actions.service';
-import {FilteringService} from '@app/services/filtering.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
+import {AuthService} from '@app/services/auth.service';
 import {TimeZoneAbbrPipe} from '@app/pipes/timezone-abbr.pipe';
 import {ModalComponent} from '@app/components/modal/modal.component';
 
@@ -90,12 +90,12 @@ describe('TimeZonePickerComponent', () => {
         ServiceLogsTruncatedService,
         TabsService,
         ComponentActionsService,
-        FilteringService,
         {
           provide: HttpClientService,
           useValue: httpClient
         },
-        LogsContainerService
+        LogsContainerService,
+        AuthService
       ],
     })
     .compileComponents();

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.html
index a7858a5..369ddd4 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.html
@@ -15,7 +15,9 @@
   limitations under the License.
 -->
 
-<menu-button *ngFor="let item of items" label="{{item.label | translate}}" [action]="item.action"
-             [iconClass]="item.iconClass" [labelClass]="item.labelClass"
-             [subItems]="item.subItems" [hideCaret]="item.hideCaret" [badge]="item.badge">
-</menu-button>
+<div class="pull-right">
+  <menu-button *ngFor="let item of items" label="{{item.label | translate}}" [action]="item.action"
+               [iconClass]="item.iconClass" [labelClass]="item.labelClass" [subItems]="item.subItems"
+               [hideCaret]="item.hideCaret" [badge]="item.badge"  [isRightAlign]="item.isRightAlign">
+  </menu-button>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.less
index 4fe899a..32d1beb 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.less
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.less
@@ -19,4 +19,5 @@
 
 :host {
   .default-flex;
+  margin-right: 0;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.ts
index 73b6131..91f27e8 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/top-menu/top-menu.component.ts
@@ -16,104 +16,28 @@
  * limitations under the License.
  */
 
-import {Component, OnInit} from '@angular/core';
+import {Component} from '@angular/core';
 
 @Component({
   selector: 'top-menu',
   templateUrl: './top-menu.component.html',
   styleUrls: ['./top-menu.component.less']
 })
-export class TopMenuComponent implements OnInit {
-
-  constructor() {
-  }
-
-  ngOnInit() {
-  }
+export class TopMenuComponent {
 
   //TODO implement loading of real data into subItems
   readonly items = [
     {
-      iconClass: 'fa fa-arrow-left',
-      label: 'topMenu.undo',
-      labelClass: 'unstyled-link',
-      action: 'undo',
-      subItems: [
-        {
-          label: 'Apply \'Last week\' filter'
-        },
-        {
-          label: 'Clear all filters'
-        },
-        {
-          label: 'Apply \'HDFS\' filter'
-        },
-        {
-          label: 'Apply \'Errors\' filter'
-        }
-      ]
-    },
-    {
-      iconClass: 'fa fa-arrow-right',
-      label: 'topMenu.redo',
-      labelClass: 'unstyled-link',
-      action: 'redo',
-      subItems: [
-        {
-          label: 'Apply \'Warnings\' filter'
-        },
-        {
-          label: 'Switch to graph mode'
-        },
-        {
-          label: 'Apply \'Custom Date\' filter'
-        }
-      ]
-    },
-    {
-      iconClass: 'fa fa-refresh',
-      label: 'topMenu.refresh',
-      labelClass: 'unstyled-link',
-      action: 'refresh'
-    },
-    {
-      iconClass: 'fa fa-history',
-      label: 'topMenu.history',
-      labelClass: 'unstyled-link',
-      action: 'openHistory',
-      subItems: [
-        {
-          label: 'Apply \'Custom Date\' filter'
-        },
-        {
-          label: 'Switch to graph mode'
-        },
-        {
-          label: 'Apply \'Warnings\' filter'
-        },
-        {
-          label: 'Apply \'Last week\' filter'
-        },
-        {
-          label: 'Clear all filters'
-        },
-        {
-          label: 'Apply \'HDFS\' filter'
-        },
-        {
-          label: 'Apply \'Errors\' filter'
-        }
-      ]
-    },
-    {
       iconClass: 'fa fa-user unstyled-link',
       hideCaret: true,
+      isRightAlign: true,
       subItems: [
         {
           label: 'Options'
         },
         {
-          label: 'Logout'
+          label: 'authorization.logout',
+          action: 'logout'
         }
       ]
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less
index 150ac56..7b7fcae 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less
@@ -61,3 +61,6 @@
 
 // Icon
 @icon-padding: 5px;
+
+// Table
+@table-border-color: #EEEEEE;

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts b/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
index 4325f5b..7578867 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
@@ -20,6 +20,7 @@ import * as moment from 'moment';
 
 export const mockData = {
   login: {},
+  logout: {},
   api: {
     v1: {
       audit: {
@@ -46,7 +47,7 @@ export const mockData = {
               proxyUsers: [
                 'admin'
               ],
-              evtTime: '2017-05-29T11:30:22.531Z',
+              evtTime: 1496057422531,
               enforcer: 'ambari-acl',
               reqContext: 'ambari',
               cliType: 'GET',
@@ -93,7 +94,7 @@ export const mockData = {
               proxyUsers: [
                 'user'
               ],
-              evtTime: '2017-05-29T11:30:22.531Z',
+              evtTime: 1496057422531,
               enforcer: 'hdfs',
               reqContext: 'ambari_server',
               cliType: 'PUT',
@@ -1064,4 +1065,4 @@ export const mockData = {
       }
     }
   }
-};
\ No newline at end of file
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts
new file mode 100644
index 0000000..65f0936
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts
@@ -0,0 +1,133 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TestBed, inject, async} from '@angular/core/testing';
+import {HttpModule} from '@angular/http';
+import {Observable} from 'rxjs/Observable';
+import 'rxjs/add/operator/first';
+import 'rxjs/add/operator/last';
+import 'rxjs/add/operator/take';
+import {StoreModule} from '@ngrx/store';
+import {AppStateService, appState} from '@app/services/storage/app-state.service';
+import {AuthService} from '@app/services/auth.service';
+import {HttpClientService} from '@app/services/http-client.service';
+
+describe('AuthService', () => {
+
+  const successResponse = {
+      type: 'default',
+      ok: true,
+      url: '/',
+      status: 200,
+      statusText: 'OK',
+      bytesLoaded: 100,
+      totalBytes: 100,
+      headers: null
+    },
+    errorResponse = {
+      type: 'error',
+      ok: false,
+      url: '/',
+      status: 401,
+      statusText: 'ERROR',
+      bytesLoaded: 100,
+      totalBytes: 100,
+      headers: null
+    };
+
+  // Note: We add delay to help the isLoginInProgress test case.
+  let httpServiceStub = {
+    isError: false,
+    postFormData: function () {
+      const isError = this.isError;
+      return Observable.create(observer => observer.next(isError ? errorResponse : successResponse)).delay(1);
+    }
+  };
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [
+        HttpModule,
+        StoreModule.provideStore({
+          appState
+        })
+      ],
+      providers: [
+        AuthService,
+        AppStateService,
+        {provide: HttpClientService, useValue: httpServiceStub}
+      ]
+    });
+  });
+
+  it('should create service', inject([AuthService], (service: AuthService) => {
+    expect(service).toBeTruthy();
+  }));
+
+  it('should set the isAuthorized state to true in appState when the login is success', async(inject(
+    [AuthService, AppStateService, HttpClientService],
+    (authService: AuthService, appStateService: AppStateService, httpClientService) => {
+      httpClientService.isError = false;
+      authService.login('test', 'test')
+        .subscribe(() => {
+          appStateService.getParameter('isAuthorized').subscribe((value: Boolean): void => {
+            expect(value).toBe(true);
+          });
+        }, value => {
+          throw value;
+        });
+    }
+  )));
+
+
+  it('should set the isAuthorized state to false in appState when the login is failed', async(inject(
+    [AuthService, AppStateService, HttpClientService],
+    (authService: AuthService, appStateService: AppStateService, httpClientService) => {
+      httpClientService.isError = true;
+      authService.login('test', 'test')
+        .subscribe(() => {
+          appStateService.getParameter('isAuthorized').subscribe((value: Boolean): void => {
+            expect(value).toBe(false);
+          });
+        });
+    }
+  )));
+
+  it('should set the isLoginInProgress state to true when the login started', async(inject(
+    [AuthService, AppStateService, HttpClientService],
+    (authService: AuthService, appStateService: AppStateService, httpClientService) => {
+      httpClientService.isError = false;
+      authService.login('test', 'test');
+      appStateService.getParameter('isLoginInProgress').first().subscribe((value: Boolean): void => {
+        expect(value).toBe(true);
+      });
+    }
+  )));
+
+  it('should set the isLoginInProgress state to true after the login is success', async(inject(
+    [AuthService, AppStateService, HttpClientService],
+    (authService: AuthService, appStateService: AppStateService, httpClientService) => {
+      httpClientService.isError = false;
+      authService.login('test', 'test');
+      appStateService.getParameter('isLoginInProgress').take(2).last().subscribe((value: Boolean): void => {
+        expect(value).toBe(false);
+      });
+    }
+  )));
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.ts
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..8785ce2
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.ts
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {Injectable} from '@angular/core';
+import {Response} from '@angular/http';
+
+import {Observable} from 'rxjs/Observable';
+
+import {HttpClientService} from '@app/services/http-client.service';
+import {AppStateService} from '@app/services/storage/app-state.service';
+
+/**
+ * This service meant to be a single place where the authorization should happen.
+ */
+@Injectable()
+export class AuthService {
+
+  constructor(private httpClient: HttpClientService, private appState: AppStateService) {}
+
+  /**
+   * The single entry point to request a login action.
+   * @param {string} username
+   * @param {string} password
+   * @returns {Observable<Response>}
+   */
+  login(username: string, password: string): Observable<Response> {
+    this.setLoginInProgressAppState(true);
+    let obs = this.httpClient.postFormData('login', {
+      username: username,
+      password: password
+    });
+    obs.subscribe(
+      (resp: Response) => this.onLoginResponse(resp),
+      (resp: Response) => this.onLoginError(resp)
+    );
+    return obs;
+  }
+
+  /**
+   * The single unique entry point to request a logout action
+   * @returns {Observable<boolean | Error>}
+   */
+  logout(): Observable<Response> {
+    let obs = this.httpClient.get('logout');
+    obs.subscribe(
+      (resp: Response) => this.onLogoutResponse(resp),
+      (resp: Response) => this.onLogoutError(resp)
+    );
+    return obs;
+  }
+
+  /**
+   * Set the isLoginInProgress state in AppState. The reason behind create a function for this is that we set this app
+   * state from two different places so let's do always the same way.
+   * @param {boolean} state the new value of the isLoginInProgress app state.
+   */
+  private setLoginInProgressAppState(state: boolean) {
+    this.appState.setParameter('isLoginInProgress', state);
+  }
+
+  /**
+   * Set the isAuthorized state in AppState. The reason behind create a function for this is that we set this app
+   * state from two different places so let's do always the same way.
+   * @param {boolean} state The new value of the isAuthorized app state.
+   */
+  private setAuthorizedAppState(state: boolean) {
+    this.appState.setParameter('isAuthorized', state);
+  }
+
+  /**
+   * Handling the login success response. The goal is to set the authorized property of the appState.
+   * @param resp
+   */
+  private onLoginResponse(resp: Response): void {
+    if (resp && resp.ok) {
+      this.setLoginInProgressAppState(false);
+      this.setAuthorizedAppState(resp.ok);
+    }
+  }
+
+  /**
+   * Handling the login error response. The goal is to set the authorized property correctly of the appState.
+   * @ToDo decide if we should have a loginError app state.
+   * @param {Reponse} resp
+   */
+  private onLoginError(resp: Response): void {
+    this.setLoginInProgressAppState(false);
+    this.setAuthorizedAppState(false);
+  }
+
+  /**
+   * Handling the logout success response. The goal is to set the authorized property of the appState.
+   * @param {Response} resp
+   */
+  private onLogoutResponse(resp: Response): void {
+    if (resp && resp.ok) {
+      this.setAuthorizedAppState(false);
+    }
+  }
+
+  /**
+   * Handling the logout error response.
+   * @ToDo decide if we should create a logoutError app state or not
+   * @param {Response} resp
+   */
+  private onLogoutError(resp: Response): void {}
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
index e6a02c0..6d43ff1 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
@@ -30,9 +30,9 @@ import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage
 import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
 import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
 import {TabsService, tabs} from '@app/services/storage/tabs.service';
-import {FilteringService} from '@app/services/filtering.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
+import {AuthService} from '@app/services/auth.service';
 
 import {ComponentActionsService} from './component-actions.service';
 
@@ -78,12 +78,12 @@ describe('ComponentActionsService', () => {
         ServiceLogsHistogramDataService,
         ServiceLogsTruncatedService,
         TabsService,
-        FilteringService,
         {
           provide: HttpClientService,
           useValue: httpClient
         },
-        LogsContainerService
+        LogsContainerService,
+        AuthService
       ]
     });
   });

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
index c483cd8..e796183 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
@@ -20,15 +20,19 @@ import {Injectable} from '@angular/core';
 import {AppSettingsService} from '@app/services/storage/app-settings.service';
 import {TabsService} from '@app/services/storage/tabs.service';
 import {CollectionModelService} from '@app/classes/models/store';
-import {FilteringService} from '@app/services/filtering.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
+import {AuthService} from '@app/services/auth.service';
 import {ServiceLog} from '@app/classes/models/service-log';
-import {getFiltersForm} from '@app/classes/filtering';
+import {ListItem} from '@app/classes/list-item';
 
 @Injectable()
 export class ComponentActionsService {
 
-  constructor(private appSettings: AppSettingsService, private tabsStorage: TabsService, private filtering: FilteringService, private logsContainer: LogsContainerService) {
+  constructor(
+    private appSettings: AppSettingsService, private tabsStorage: TabsService,
+    private logsContainer: LogsContainerService,
+    private authService: AuthService
+  ) {
   }
 
   //TODO implement actions
@@ -81,7 +85,6 @@ export class ComponentActionsService {
     const tab = {
       id: log.id,
       type: 'serviceLogs',
-      isActive: true,
       isCloseable: true,
       label: `${log.host} >> ${log.type}`,
       appState: {
@@ -92,7 +95,14 @@ export class ComponentActionsService {
           host_name: log.host,
           component_name: log.type
         },
-        activeFiltersForm: getFiltersForm('serviceLogs')
+        activeFilters: Object.assign(this.logsContainer.getFiltersData('serviceLogs'), {
+          components: this.logsContainer.filters.components.options.find((option: ListItem): boolean => {
+            return option.value === log.type;
+          }),
+          hosts: this.logsContainer.filters.hosts.options.find((option: ListItem): boolean => {
+            return option.value === log.host;
+          })
+        })
       }
     };
     this.tabsStorage.addInstance(tab);
@@ -104,11 +114,11 @@ export class ComponentActionsService {
   }
 
   startCapture(): void {
-    this.filtering.startCaptureTimer();
+    this.logsContainer.startCaptureTimer();
   }
 
   stopCapture(): void {
-    this.filtering.stopCaptureTimer();
+    this.logsContainer.stopCaptureTimer();
   }
 
   setTimeZone(timeZone: string): void {
@@ -121,9 +131,25 @@ export class ComponentActionsService {
     }));
   }
 
-  proceedWithExclude = (item: string): void => this.filtering.queryParameterNameChange.next({
+  proceedWithExclude = (item: string): void => this.logsContainer.queryParameterNameChange.next({
     item: item,
     isExclude: true
   });
 
+  /**
+   * Request a login action from the AuthService
+   * @param {string} username
+   * @param {string} password
+   */
+  login(username: string, password: string): void {
+    this.authService.login(username, password);
+  }
+
+  /**
+   * Request a logout action from AuthService
+   */
+  logout(): void {
+    this.authService.logout();
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
index 5dc38b4..a161190 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
@@ -32,7 +32,6 @@ import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/s
 import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {HttpClientService} from '@app/services/http-client.service';
-import {FilteringService} from '@app/services/filtering.service';
 
 import {ComponentGeneratorService} from './component-generator.service';
 
@@ -70,7 +69,6 @@ describe('ComponentGeneratorService', () => {
           provide: HttpClientService,
           useValue: httpClient
         },
-        FilteringService,
         HostsService,
         AuditLogsService,
         ServiceLogsService,

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts
deleted file mode 100644
index 2b3e326..0000000
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import {TestBed, inject} from '@angular/core/testing';
-import {StoreModule} from '@ngrx/store';
-import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
-import {AppStateService, appState} from '@app/services/storage/app-state.service';
-import {ClustersService, clusters} from '@app/services/storage/clusters.service';
-import {ComponentsService, components} from '@app/services/storage/components.service';
-import {HostsService, hosts} from '@app/services/storage/hosts.service';
-import {UtilsService} from '@app/services/utils.service';
-import {HttpClientService} from '@app/services/http-client.service';
-import {ListItem} from '@app/classes/list-item';
-import {Node} from '@app/classes/models/node';
-
-import {FilteringService} from './filtering.service';
-
-describe('FilteringService', () => {
-  beforeEach(() => {
-    const httpClient = {
-      get: () => {
-        return {
-          subscribe: () => {
-          }
-        }
-      }
-    };
-    TestBed.configureTestingModule({
-      imports: [
-        StoreModule.provideStore({
-          appSettings,
-          appState,
-          clusters,
-          components,
-          hosts
-        })
-      ],
-      providers: [
-        FilteringService,
-        AppSettingsService,
-        AppStateService,
-        ClustersService,
-        ComponentsService,
-        HostsService,
-        UtilsService,
-        {
-          provide: HttpClientService,
-          useValue: httpClient
-        }
-      ]
-    });
-  });
-
-  it('should create service', inject([FilteringService], (service: FilteringService) => {
-    expect(service).toBeTruthy();
-  }));
-
-  describe('#getListItemFromString()', () => {
-    it('should convert string to ListItem', inject([FilteringService], (service: FilteringService) => {
-      const getListItemFromString: (name: string) => ListItem = service['getListItemFromString'];
-      expect(getListItemFromString('customName')).toEqual({
-        label: 'customName',
-        value: 'customName'
-      });
-    }));
-  });
-
-  describe('#getListItemFromNode()', () => {
-    it('should convert Node to ListItem', inject([FilteringService], (service: FilteringService) => {
-      const getListItemFromNode: (node: Node) => ListItem = service['getListItemFromNode'];
-      expect(getListItemFromNode({
-        name: 'customName',
-        value: '1',
-        isParent: true,
-        isRoot: true
-      })).toEqual({
-        label: 'customName (1)',
-        value: 'customName'
-      });
-    }));
-  });
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
deleted file mode 100644
index 85dc408..0000000
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
+++ /dev/null
@@ -1,253 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import {Injectable, Input} from '@angular/core';
-import {FormGroup} from '@angular/forms';
-import {Response} from '@angular/http';
-import {Subject} from 'rxjs/Subject';
-import {Observable} from 'rxjs/Observable';
-import 'rxjs/add/observable/timer';
-import 'rxjs/add/operator/takeUntil';
-import * as moment from 'moment-timezone';
-import {ListItem} from '@app/classes/list-item';
-import {FilterCondition, filters} from '@app/classes/filtering';
-import {Node} from '@app/classes/models/node';
-import {AppSettingsService} from '@app/services/storage/app-settings.service';
-import {ClustersService} from '@app/services/storage/clusters.service';
-import {ComponentsService} from '@app/services/storage/components.service';
-import {HostsService} from '@app/services/storage/hosts.service';
-import {AppStateService} from '@app/services/storage/app-state.service';
-import {HttpClientService} from '@app/services/http-client.service';
-
-@Injectable()
-export class FilteringService {
-
-  constructor(private httpClient: HttpClientService, private appSettings: AppSettingsService, private clustersStorage: ClustersService, private componentsStorage: ComponentsService, private hostsStorage: HostsService, private appState: AppStateService) {
-    this.loadClusters();
-    this.loadComponents();
-    this.loadHosts();
-    appSettings.getParameter('timeZone').subscribe(value => this.timeZone = value || this.defaultTimeZone);
-    clustersStorage.getAll().subscribe((clusters: string[]): void => {
-      this.filters.clusters.options = [...this.filters.clusters.options, ...clusters.map(this.getListItemFromString)];
-    });
-    componentsStorage.getAll().subscribe((components: Node[]): void => {
-     this.filters.components.options = [...this.filters.components.options, ...components.map(this.getListItemFromNode)];
-    });
-    hostsStorage.getAll().subscribe((hosts: Node[]): void => {
-      this.filters.hosts.options = [...this.filters.hosts.options, ...hosts.map(this.getListItemFromNode)];
-    });
-    appState.getParameter('activeFiltersForm').subscribe((form: FormGroup) => this.activeFiltersForm = form);
-  }
-
-  /**
-   * Get instance for dropdown list from string
-   * @param name {string}
-   * @returns {ListItem}
-   */
-  private getListItemFromString(name: string): ListItem {
-    return {
-      label: name,
-      value: name
-    };
-  }
-
-  /**
-   * Get instance for dropdown list from Node object
-   * @param node {Node}
-   * @returns {ListItem}
-   */
-  private getListItemFromNode(node: Node): ListItem {
-    return {
-      label: `${node.name} (${node.value})`,
-      value: node.name
-    };
-  }
-
-  private readonly defaultTimeZone = moment.tz.guess();
-
-  timeZone: string = this.defaultTimeZone;
-
-  /**
-   * A configurable property to indicate the maximum capture time in milliseconds.
-   * @type {number}
-   * @default 600000 (10 minutes)
-   */
-  @Input()
-  maximumCaptureTimeLimit: number = 600000;
-
-  filters: {[key: string]: FilterCondition} = Object.assign({}, filters);
-
-  activeFiltersForm: FormGroup;
-
-  queryParameterNameChange: Subject<any> = new Subject();
-
-  queryParameterAdd: Subject<any> = new Subject();
-
-  private stopTimer: Subject<any> = new Subject();
-
-  private stopAutoRefreshCountdown: Subject<any> = new Subject();
-
-  captureSeconds: number = 0;
-
-  private readonly autoRefreshInterval: number = 30000;
-
-  autoRefreshRemainingSeconds: number = 0;
-
-  private startCaptureTime: number;
-
-  private stopCaptureTime: number;
-
-  startCaptureTimer(): void {
-    this.startCaptureTime = new Date().valueOf();
-    const maxCaptureTimeInSeconds = this.maximumCaptureTimeLimit / 1000;
-    Observable.timer(0, 1000).takeUntil(this.stopTimer).subscribe((seconds: number): void => {
-      this.captureSeconds = seconds;
-      if (this.captureSeconds >= maxCaptureTimeInSeconds) {
-        this.stopCaptureTimer();
-      }
-    });
-  }
-
-  stopCaptureTimer(): void {
-    const autoRefreshIntervalSeconds = this.autoRefreshInterval / 1000;
-    this.stopCaptureTime = new Date().valueOf();
-    this.captureSeconds = 0;
-    this.stopTimer.next();
-    this.setCustomTimeRange(this.startCaptureTime, this.stopCaptureTime);
-    Observable.timer(0, 1000).takeUntil(this.stopAutoRefreshCountdown).subscribe((seconds: number): void => {
-      this.autoRefreshRemainingSeconds = autoRefreshIntervalSeconds - seconds;
-      if (!this.autoRefreshRemainingSeconds) {
-        this.stopAutoRefreshCountdown.next();
-        this.setCustomTimeRange(this.startCaptureTime, this.stopCaptureTime);
-      }
-    });
-  }
-
-  loadClusters(): void {
-    this.httpClient.get('clusters').subscribe((response: Response): void => {
-      const clusterNames = response.json();
-      if (clusterNames) {
-        this.clustersStorage.addInstances(clusterNames);
-      }
-    });
-  }
-
-  loadComponents(): void {
-    this.httpClient.get('components').subscribe((response: Response): void => {
-      const jsonResponse = response.json(),
-        components = jsonResponse && jsonResponse.vNodeList.map((item): Node => Object.assign(item, {
-            value: item.logLevelCount.reduce((currentValue: number, currentItem): number => {
-              return currentValue + Number(currentItem.value);
-            }, 0)
-          }));
-      if (components) {
-        this.componentsStorage.addInstances(components);
-      }
-    });
-  }
-
-  loadHosts(): void {
-    this.httpClient.get('hosts').subscribe((response: Response): void => {
-      const jsonResponse = response.json(),
-        hosts = jsonResponse && jsonResponse.vNodeList;
-      if (hosts) {
-        this.hostsStorage.addInstances(hosts);
-      }
-    });
-  }
-
-  setCustomTimeRange(startTime: number, endTime: number): void {
-    this.activeFiltersForm.controls.timeRange.setValue({
-      type: 'CUSTOM',
-      start: moment(startTime),
-      end: moment(endTime)
-    });
-  }
-
-  private getStartTime = (value: any, current: string): string => {
-    let time;
-    if (value) {
-      const endTime = moment(moment(current).valueOf());
-      switch (value.type) {
-        case 'LAST':
-          time = endTime.subtract(value.interval, value.unit);
-          break;
-        case 'CURRENT':
-          time = moment().tz(this.timeZone).startOf(value.unit);
-          break;
-        case 'PAST':
-          time = endTime.startOf(value.unit);
-          break;
-        case 'CUSTOM':
-          time = value.start;
-          break;
-        default:
-          break;
-      }
-    }
-    return time ? time.toISOString() : '';
-  };
-
-  private getEndTime = (value: any): string => {
-    let time;
-    if (value) {
-      switch (value.type) {
-        case 'LAST':
-          time = moment();
-          break;
-        case 'CURRENT':
-          time = moment().tz(this.timeZone).endOf(value.unit);
-          break;
-        case 'PAST':
-          time = moment().tz(this.timeZone).startOf(value.unit).millisecond(-1);
-          break;
-        case 'CUSTOM':
-          time = value.end;
-          break;
-        default:
-          break;
-      }
-    }
-    return time ? time.toISOString() : '';
-  };
-
-  private getQuery(isExclude: boolean): (value: any[]) => string {
-    return (value: any[]): string => {
-      let parameters;
-      if (value && value.length) {
-        parameters = value.filter(item => item.isExclude === isExclude).map(parameter => {
-          return {
-            [parameter.name]: parameter.value.replace(/\s/g, '+')
-          };
-        });
-      }
-      return parameters && parameters.length ? JSON.stringify(parameters) : '';
-    }
-  }
-
-  readonly valueGetters = {
-    to: this.getEndTime,
-    from: this.getStartTime,
-    sortType: value => value && value.type,
-    sortBy: value => value && value.key,
-    page: value => value == null ? value : value.toString(),
-    includeQuery: this.getQuery(false),
-    excludeQuery: this.getQuery(true)
-  };
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts
index ee0e1e7..47cb25d 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts
@@ -31,7 +31,8 @@ import {HostsService, hosts} from '@app/services/storage/hosts.service';
 import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
 import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {HttpClientService} from '@app/services/http-client.service';
-import {FilteringService} from '@app/services/filtering.service';
+import {ListItem} from '@app/classes/list-item';
+import {NodeItem} from '@app/classes/models/node-item';
 
 import {LogsContainerService} from './logs-container.service';
 
@@ -79,8 +80,7 @@ describe('LogsContainerService', () => {
         {
           provide: HttpClientService,
           useValue: httpClient
-        },
-        FilteringService
+        }
       ]
     });
   });
@@ -88,4 +88,29 @@ describe('LogsContainerService', () => {
   it('should create service', inject([LogsContainerService], (service: LogsContainerService) => {
     expect(service).toBeTruthy();
   }));
+
+  describe('#getListItemFromString()', () => {
+    it('should convert string to ListItem', inject([LogsContainerService], (service: LogsContainerService) => {
+      const getListItemFromString: (name: string) => ListItem = service['getListItemFromString'];
+      expect(getListItemFromString('customName')).toEqual({
+        label: 'customName',
+        value: 'customName'
+      });
+    }));
+  });
+
+  describe('#getListItemFromNode()', () => {
+    it('should convert NodeItem to ListItem', inject([LogsContainerService], (service: LogsContainerService) => {
+      const getListItemFromNode: (node: NodeItem) => ListItem = service['getListItemFromNode'];
+      expect(getListItemFromNode({
+        name: 'customName',
+        value: '1',
+        isParent: true,
+        isRoot: true
+      })).toEqual({
+        label: 'customName (1)',
+        value: 'customName'
+      });
+    }));
+  });
 });