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 79504f7  AMBARI-22835 Log Search UI: implement log level filter
79504f7 is described below

commit 79504f74e83164a9c70713ea54cfc2f257d5be04
Author: aBabiichuk <ababiic...@hortonworks.com>
AuthorDate: Sat Feb 3 13:46:48 2018 +0200

    AMBARI-22835 Log Search UI: implement log level filter
---
 .../ambari-logsearch-web/src/app/app.module.ts     |    6 +-
 .../src/app/classes/models/app-settings.ts         |    8 +-
 .../src/app/classes/models/filter.ts               |    8 +-
 .../src/app/classes/models/store.ts                |   10 +-
 .../ambari-logsearch-web/src/app/classes/object.ts |    8 +
 .../app/classes/{models/filter.ts => settings.ts}  |   17 +-
 .../ambari-logsearch-web/src/app/classes/string.ts |    2 +
 .../action-menu/action-menu.component.html         |   14 +-
 .../action-menu/action-menu.component.spec.ts      |   11 +-
 .../action-menu/action-menu.component.ts           |   30 +-
 .../date-picker/date-picker.component.ts           |   21 +-
 .../log-index-filter.component.html                |   86 ++
 .../log-index-filter.component.less}               |   40 +-
 .../log-index-filter.component.spec.ts}            |   26 +-
 .../log-index-filter/log-index-filter.component.ts |  177 +++
 .../logs-container/logs-container.component.ts     |   20 +-
 .../src/app/components/modal/modal.component.html  |    5 +-
 .../src/app/components/modal/modal.component.less  |   22 +
 .../src/app/components/modal/modal.component.ts    |    9 +-
 .../service-logs-table.component.less              |    2 +-
 .../timezone-picker.component.spec.ts              |    6 +-
 .../timezone-picker/timezone-picker.component.ts   |    8 +-
 .../src/app/components/variables.less              |    5 +-
 .../ambari-logsearch-web/src/app/mock-data.ts      | 1484 +++++++++++++++++++-
 .../app/services/component-generator.service.ts    |    9 +-
 .../src/app/services/http-client.service.ts        |    9 +-
 .../app/services/logs-container.service.spec.ts    |   26 -
 .../src/app/services/logs-container.service.ts     |  116 +-
 .../src/app/services/storage/reducers.service.ts   |    2 -
 .../user-settings.service.spec.ts}                 |   36 +-
 .../src/app/services/user-settings.service.ts      |  162 +++
 .../src/app/services/utils.service.spec.ts         |   24 +
 .../src/app/services/utils.service.ts              |   26 +
 .../ambari-logsearch-web/src/assets/i18n/en.json   |   13 +-
 34 files changed, 2202 insertions(+), 246 deletions(-)

diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
index 0a42994..5a2b59d 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
@@ -38,6 +38,7 @@ import {HttpClientService} from 
'@app/services/http-client.service';
 import {UtilsService} from '@app/services/utils.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {ComponentGeneratorService} from 
'@app/services/component-generator.service';
+import {UserSettingsService} from '@app/services/user-settings.service';
 
 import {AppSettingsService} from '@app/services/storage/app-settings.service';
 import {AppStateService} from '@app/services/storage/app-state.service';
@@ -49,7 +50,6 @@ import {ServiceLogsTruncatedService} from 
'@app/services/storage/service-logs-tr
 import {GraphsService} from '@app/services/storage/graphs.service';
 import {HostsService} from '@app/services/storage/hosts.service';
 import {UserConfigsService} from '@app/services/storage/user-configs.service';
-import {FiltersService} from '@app/services/storage/filters.service';
 import {ClustersService} from '@app/services/storage/clusters.service';
 import {ComponentsService} from '@app/services/storage/components.service';
 import {ServiceLogsFieldsService} from 
'@app/services/storage/service-logs-fields.service';
@@ -97,6 +97,7 @@ import {GraphLegendItemComponent} from 
'@app/components/graph-legend-item/graph-
 import {TimeLineGraphComponent} from 
'@app/components/time-line-graph/time-line-graph.component';
 import {ContextMenuComponent} from 
'@app/components/context-menu/context-menu.component';
 import {HistoryItemControlsComponent} from 
'@app/components/history-item-controls/history-item-controls.component';
+import {LogIndexFilterComponent} from 
'@app/components/log-index-filter/log-index-filter.component';
 
 import {TimeZoneAbbrPipe} from '@app/pipes/timezone-abbr.pipe';
 import {TimerSecondsPipe} from '@app/pipes/timer-seconds.pipe';
@@ -161,6 +162,7 @@ export function getXHRBackend(injector: Injector, browser: 
BrowserXhr, xsrf: XSR
     TimeLineGraphComponent,
     ContextMenuComponent,
     HistoryItemControlsComponent,
+    LogIndexFilterComponent,
     TimeZoneAbbrPipe,
     TimerSecondsPipe
   ],
@@ -188,6 +190,7 @@ export function getXHRBackend(injector: Injector, browser: 
BrowserXhr, xsrf: XSR
     UtilsService,
     LogsContainerService,
     ComponentGeneratorService,
+    UserSettingsService,
     AppSettingsService,
     AppStateService,
     AuditLogsService,
@@ -198,7 +201,6 @@ export function getXHRBackend(injector: Injector, browser: 
BrowserXhr, xsrf: XSR
     GraphsService,
     HostsService,
     UserConfigsService,
-    FiltersService,
     ClustersService,
     ComponentsService,
     ServiceLogsFieldsService,
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-settings.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-settings.ts
index 11821a3..3ba5089 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-settings.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-settings.ts
@@ -17,11 +17,15 @@
  */
 
 import * as moment from 'moment-timezone';
+import {HomogeneousObject} from '@app/classes/object';
+import {Filter} from '@app/classes/models/filter';
 
 export interface AppSettings {
   timeZone: string;
+  logIndexFilters: HomogeneousObject<HomogeneousObject<Filter>>;
 }
 
 export const defaultSettings: AppSettings = {
-  timeZone: moment.tz.guess()
-}
+  timeZone: moment.tz.guess(),
+  logIndexFilters: {}
+};
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/filter.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/filter.ts
index c7ff662..b3e01aa 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/filter.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/filter.ts
@@ -16,10 +16,12 @@
  * limitations under the License.
  */
 
+import {LogLevel} from '@app/classes/string';
+
 export interface Filter {
   label: string;
   hosts: string[];
-  defaultLevels: string[];
-  overrideLevels: string[];
-  expiryTime: string;
+  defaultLevels: LogLevel[];
+  overrideLevels: LogLevel[];
+  expiryTime: string | null;
 }
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts
index f2d0696..1764c93 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts
@@ -26,12 +26,11 @@ import {BarGraph} from '@app/classes/models/bar-graph';
 import {Graph} from '@app/classes/models/graph';
 import {NodeItem} from '@app/classes/models/node-item';
 import {UserConfig} from '@app/classes/models/user-config';
-import {Filter} from '@app/classes/models/filter';
 import {AuditLogField} from '@app/classes/models/audit-log-field';
 import {ServiceLogField} from '@app/classes/models/service-log-field';
 import {Tab} from '@app/classes/models/tab';
 
-export const storeActions = {
+const storeActions = {
   'ARRAY.ADD': 'ADD',
   'ARRAY.ADD.START': 'ADD_TO_START',
   'ARRAY.DELETE.PRIMITIVE': 'DELETE_PRIMITIVE',
@@ -53,7 +52,6 @@ export interface AppStore {
   graphs: Graph[];
   hosts: NodeItem[];
   userConfigs: UserConfig[];
-  filters: Filter[];
   clusters: string[];
   components: NodeItem[];
   serviceLogsFields: ServiceLogField[];
@@ -144,9 +142,9 @@ export class ObjectModelService extends ModelService {
   }
 
   setParameter(key: string, value: any): void {
-    let payload = {};
-    payload[key] = value;
-    this.setParameters(payload);
+    this.setParameters({
+      [key]: value
+    });
   }
 
   setParameters(params: any): void {
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/object.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/object.ts
index 4d0c7f6..13cc4cc 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/object.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/object.ts
@@ -16,4 +16,12 @@
  * limitations under the License.
  */
 
+import {LogLevel} from '@app/classes/string';
+
 export type HomogeneousObject<T> = {[key: string]: T};
+
+export interface LogLevelObject {
+  name: LogLevel;
+  label: string;
+  color: string;
+}
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/filter.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/settings.ts
similarity index 72%
copy from ambari-logsearch/ambari-logsearch-web/src/app/classes/models/filter.ts
copy to ambari-logsearch/ambari-logsearch-web/src/app/classes/settings.ts
index c7ff662..dcef457 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/filter.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/settings.ts
@@ -16,10 +16,17 @@
  * limitations under the License.
  */
 
-export interface Filter {
+import {HomogeneousObject} from '@app/classes/object';
+
+export type LevelOverridesConfig = HomogeneousObject<{
+  defaults: boolean;
+  overrides: boolean;
+}>
+
+export type LogIndexFilterComponentConfig = LevelOverridesConfig & {
+  name: string;
   label: string;
-  hosts: string[];
-  defaultLevels: string[];
-  overrideLevels: string[];
-  expiryTime: string;
+  hosts: string;
+  expiryTime: string | null;
+  hasOverrides?: boolean;
 }
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/string.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/string.ts
index 21ff4ca..a8156e6 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/string.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/string.ts
@@ -23,3 +23,5 @@ export type TimeRangeType = 'CURRENT' | 'LAST' | 'PAST';
 export type SortingType = 'asc' | 'desc';
 
 export type ScrollType = 'before' | 'after' | '';
+
+export type LogLevel = 'FATAL' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' 
| 'UNKNOWN';
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html
index 2e332d4..78fb277 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html
@@ -19,9 +19,21 @@
 <menu-button label="{{'topMenu.undo' | translate}}" [subItems]="undoItems" 
iconClass="fa fa-arrow-left"
              listClass="history-dropdown" (buttonClick)="undoLatest()" 
(selectItem)="undo($event)"></menu-button>
 <menu-button label="{{'topMenu.redo' | translate}}" [subItems]="redoItems" 
iconClass="fa fa-arrow-right"
-             listClass="history-dropdown" (buttonClick)="redoLatest()" 
(selectItem)="redo($event)">></menu-button>
+             listClass="history-dropdown" (buttonClick)="redoLatest()" 
(selectItem)="redo($event)"></menu-button>
 <menu-button label="{{'topMenu.history' | translate}}" 
[subItems]="historyItems" iconClass="fa fa-history"
              listClass="history-dropdown" [isRightAlign]="true"
              
additionalLabelComponentSetter="getHistoryItemIcons"></menu-button>
+<menu-button label="{{'topMenu.filter' | translate}}" iconClass="fa fa-filter"
+             (buttonClick)="openLogIndexFilter()"></menu-button>
 <menu-button label="{{'topMenu.refresh' | translate}}" iconClass="fa 
fa-refresh"
              (buttonClick)="refresh()"></menu-button>
+<modal *ngIf="isLogIndexFilterDisplayed" (submit)="saveLogIndexFilter()" 
(cancel)="closeLogIndexFilter()"
+       (close)="closeLogIndexFilter()" [isExtraLargeModal]="true" 
[isSubmitDisabled]="isModalSubmitDisabled"
+       title="{{'logIndexFilter.title' | translate}}" 
submitButtonLabel="{{'modal.save' | translate}}">
+  <ng-template>
+    <form [formGroup]="settingsForm">
+      <log-index-filter formControlName="logIndexFilter"
+                        
(changeIsSubmitDisabled)="setModalSubmitDisabled($event)"></log-index-filter>
+    </form>
+  </ng-template>
+</modal>
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
index ba53ee1..71676ac 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
@@ -18,6 +18,7 @@
 
 import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
 import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
 import {TranslationModules} from '@app/test-config.spec';
 import {StoreModule} from '@ngrx/store';
 import {AuditLogsService, auditLogs} from 
'@app/services/storage/audit-logs.service';
@@ -38,7 +39,9 @@ import {TabsService, tabs} from 
'@app/services/storage/tabs.service';
 import {HistoryManagerService} from '@app/services/history-manager.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
+import {UserSettingsService} from '@app/services/user-settings.service';
 import {UtilsService} from '@app/services/utils.service';
+import {ModalComponent} from '@app/components/modal/modal.component';
 
 import {ActionMenuComponent} from './action-menu.component';
 
@@ -57,6 +60,8 @@ describe('ActionMenuComponent', () => {
     };
     TestBed.configureTestingModule({
       imports: [
+        FormsModule,
+        ReactiveFormsModule,
         ...TranslationModules,
         StoreModule.provideStore({
           auditLogs,
@@ -74,7 +79,10 @@ describe('ActionMenuComponent', () => {
           tabs
         })
       ],
-      declarations: [ActionMenuComponent],
+      declarations: [
+        ActionMenuComponent,
+        ModalComponent
+      ],
       providers: [
         {
           provide: HttpClientService,
@@ -82,6 +90,7 @@ describe('ActionMenuComponent', () => {
         },
         HistoryManagerService,
         LogsContainerService,
+        UserSettingsService,
         UtilsService,
         AuditLogsService,
         ServiceLogsService,
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
index 351268c..21ce307 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
@@ -17,8 +17,10 @@
  */
 
 import {Component} from '@angular/core';
+import {FormGroup} from '@angular/forms';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {HistoryManagerService} from '@app/services/history-manager.service';
+import {UserSettingsService} from '@app/services/user-settings.service';
 import {ListItem} from '@app/classes/list-item';
 
 @Component({
@@ -28,7 +30,10 @@ import {ListItem} from '@app/classes/list-item';
 })
 export class ActionMenuComponent {
 
-  constructor(private logsContainer: LogsContainerService, private 
historyManager: HistoryManagerService) {
+  constructor(
+    private logsContainer: LogsContainerService, private historyManager: 
HistoryManagerService,
+    private settings: UserSettingsService
+  ) {
   }
 
   get undoItems(): ListItem[] {
@@ -43,6 +48,16 @@ export class ActionMenuComponent {
     return this.historyManager.activeHistory;
   }
 
+  isLogIndexFilterDisplayed: boolean = false;
+
+  settingsForm: FormGroup = this.settings.settingsFormGroup;
+
+  isModalSubmitDisabled: boolean = true;
+
+  setModalSubmitDisabled(isDisabled: boolean): void {
+    this.isModalSubmitDisabled = isDisabled;
+  }
+
   undoLatest(): void {
     this.historyManager.undo(this.undoItems[0]);
   }
@@ -63,4 +78,17 @@ export class ActionMenuComponent {
     this.logsContainer.loadLogs();
   }
 
+  openLogIndexFilter(): void {
+    this.isLogIndexFilterDisplayed = true;
+  }
+
+  closeLogIndexFilter(): void {
+    this.isLogIndexFilterDisplayed = false;
+  }
+
+  saveLogIndexFilter(): void {
+    this.isLogIndexFilterDisplayed = false;
+    this.settings.saveIndexFilterConfig();
+  }
+
 }
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
index e33d71e..93ebe37 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
@@ -20,7 +20,7 @@ import {
   Component, OnInit, OnChanges, OnDestroy, SimpleChanges, Input, Output, 
EventEmitter, ViewChild, ElementRef
 } from '@angular/core';
 import * as $ from 'jquery';
-import {Moment} from 'moment-timezone';
+import * as moment from 'moment';
 import '@vendor/js/bootstrap-datetimepicker.min';
 import {AppSettingsService} from '@app/services/storage/app-settings.service';
 
@@ -31,16 +31,16 @@ import {AppSettingsService} from 
'@app/services/storage/app-settings.service';
 export class DatePickerComponent implements OnInit, OnChanges, OnDestroy {
 
   constructor(private appSettings: AppSettingsService) {
-    appSettings.getParameter('timeZone').subscribe((value: string): void => {
+  }
+
+  ngOnInit(): void {
+    this.appSettings.getParameter('timeZone').subscribe((value: string): void 
=> {
       this.destroyDatePicker();
       this.timeZone = value;
       if (this.datePickerElement) {
         this.createDatePicker();
       }
     });
-  }
-
-  ngOnInit(): void {
     this.createDatePicker();
   }
 
@@ -56,10 +56,10 @@ export class DatePickerComponent implements OnInit, 
OnChanges, OnDestroy {
 
   /**
    * Value of time input field passed from parent component
-   * @type {Moment}
+   * @type {Moment|Date|string}
    */
   @Input()
-  time: Moment;
+  time: moment.Moment | Date | string;
 
   @Output()
   timeChange: EventEmitter<number> = new EventEmitter();
@@ -89,10 +89,11 @@ export class DatePickerComponent implements OnInit, 
OnChanges, OnDestroy {
 
   /**
    * Set value to time input field
-   * @param {Moment} time
+   * @param {Moment|Date|string} time
    */
-  private setTime(time: Moment): void {
-    this.datePickerElement.data('DateTimePicker').date(time);
+  private setTime(time: moment.Moment | Date | string): void {
+    const timeMoment = moment.isMoment(time) ? time : moment(time);
+    this.datePickerElement.data('DateTimePicker').date(timeMoment);
   }
 
 }
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.html
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.html
new file mode 100644
index 0000000..50d7742
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.html
@@ -0,0 +1,86 @@
+<!--
+  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.
+-->
+
+<div>{{'logIndexFilter.caption' | translate}}</div>
+<h5>{{'logIndexFilter.selectCluster' | translate}}</h5>
+<dropdown-button [options]="clustersListItems | async" 
(selectItem)="setActiveCluster($event)"
+                 label="{{'logIndexFilter.select' | translate}}" 
buttonClass="btn-default"></dropdown-button>
+<table *ngIf="activeClusterName" class="table table-hover">
+  <thead>
+    <tr>
+      <th class="component-column">{{'filter.components' | translate}}</th>
+      <th *ngFor="let column of columns" class="checkbox-column">
+        <input type="checkbox" attr.id="{{column.name}}"
+               [attr.checked]="isAllComponentsCheckedForLevel(column.name) ? 
'checked' : null"
+               (change)="processAllComponentsForLevel(column.name, 
$event.target.checked)">
+        <label attr.for="{{column.name}}">
+          <graph-legend-item label="{{column.label | translate}}" 
color="{{column.color}}"></graph-legend-item>
+        </label>
+      </th>
+      <th class="override-column">{{'logIndexFilter.override' | 
translate}}</th>
+    </tr>
+  </thead>
+  <tbody>
+    <ng-container *ngFor="let component of activeClusterConfigs">
+      <tr>
+        <td class="component-column">
+          <input type="checkbox" attr.id="{{component.name}}"
+                 
[attr.checked]="isAllLevelsCheckedForComponent(component.name) ? 'checked' : 
null"
+                 (change)="processAllLevelsForComponent(component.name, 
$event.target.checked)">
+          <label attr.for="{{component.name}}">{{component.label}}</label>
+        </td>
+        <td *ngFor="let levelName of levelNames" class="checkbox-column">
+          <input type="checkbox" attr.id="{{getCheckBoxId(component.name, 
levelName)}}"
+                 [(ngModel)]="component[levelName].defaults" 
(change)="updateValue()">
+          <label attr.for="{{getCheckBoxId(component.name, 
levelName)}}">&nbsp;</label>
+        </td>
+        <td class="override-column">
+          <span class="overrides-toggle">{{'logIndexFilter.addHosts' | 
translate}}</span>
+        </td>
+      </tr>
+      <tr> <!--overrides row -->
+        <td class="component-column">
+          <input type="checkbox" attr.id="{{component.name}}_overrides"
+                 
[attr.checked]="isAllLevelsCheckedForComponent(component.name, true) ? 
'checked' : null"
+                 (change)="processAllLevelsForComponent(component.name, 
$event.target.checked, true)">
+          <label attr.for="{{component.name}}_overrides">&nbsp;</label>
+        </td>
+        <td *ngFor="let levelName of levelNames" class="checkbox-column">
+          <input type="checkbox" attr.id="{{getCheckBoxId(component.name, 
levelName, true)}}"
+                 [(ngModel)]="component[levelName].overrides" 
(change)="updateValue()">
+          <label attr.for="{{getCheckBoxId(component.name, levelName, 
true)}}">&nbsp;</label>
+        </td>
+        <td class="override-column">
+          <div class="col-md-12 row">
+            <div class="col-md-6">
+              <div class="text-uppercase">{{'logIndexFilter.hostname' | 
translate}}</div>
+              <input type="text" class="form-control" 
[(ngModel)]="component.hosts" (change)="updateValue()">
+              <!-- TODO implement typeahead similar to search box
+                   (some functionality and appearance most likely will be 
shared) -->
+              <!-- <input type="text" class="form-control" 
[(ngModel)]="component.hosts" (change)="updateValue()"
+                     [typeahead]="hosts | async" typeaheadOptionField="name"> 
-->
+            </div>
+            <div class=" col-md-6">
+              <div class="text-uppercase">{{'logIndexFilter.expiryDate' | 
translate}}</div>
+              <date-picker [time]="component.expiryTime" 
(timeChange)="setExpiryTime($event, component)"></date-picker>
+            </div>
+          </div>
+        </td>
+      </tr>
+    </ng-container>
+  </tbody>
+</table>
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/filters.service.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
similarity index 62%
rename from 
ambari-logsearch/ambari-logsearch-web/src/app/services/storage/filters.service.ts
rename to 
ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
index 493e2e6..f932258 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/filters.service.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
@@ -16,18 +16,38 @@
  * limitations under the License.
  */
 
+@import '../mixins';
 
-import {Injectable} from '@angular/core';
-import {Store} from '@ngrx/store';
-import {AppStore, CollectionModelService, getCollectionReducer} from 
'@app/classes/models/store';
+table {
+  display: block;
+  max-height: 70vh;
+  overflow-y: auto;
+  table-layout: fixed;
 
-export const modelName = 'filters';
+  .component-column {
+    width: auto;
+  }
+
+  .checkbox-column {
+    width: 100px;
+    padding-left: 0;
+    padding-right: 0;
 
-@Injectable()
-export class FiltersService extends CollectionModelService {
-  constructor(store: Store<AppStore>) {
-    super(modelName, store);
+    /deep/ graph-legend-item {
+      padding-right: 1px;
+    }
+  }
+
+  .override-column {
+    width: 32%;
+    padding-right: 0;
   }
-}
 
-export const filters = getCollectionReducer(modelName);
+  .overrides-toggle {
+    .clickable-item;
+  }
+
+  input[type=checkbox] + label {
+    font-size: @table-font-size;
+  }
+}
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.spec.ts
similarity index 81%
copy from 
ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
copy to 
ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.spec.ts
index ba53ee1..a236686 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.spec.ts
@@ -18,6 +18,7 @@
 
 import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
 import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {FormsModule} from '@angular/forms';
 import {TranslationModules} from '@app/test-config.spec';
 import {StoreModule} from '@ngrx/store';
 import {AuditLogsService, auditLogs} from 
'@app/services/storage/audit-logs.service';
@@ -35,16 +36,19 @@ import {ComponentsService, components} from 
'@app/services/storage/components.se
 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 {HistoryManagerService} from '@app/services/history-manager.service';
+import {ComponentGeneratorService} from 
'@app/services/component-generator.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
+import {UserSettingsService} from '@app/services/user-settings.service';
 import {UtilsService} from '@app/services/utils.service';
+import {DropdownButtonComponent} from 
'@app/components/dropdown-button/dropdown-button.component';
+import {DropdownListComponent} from 
'@app/components/dropdown-list/dropdown-list.component';
 
-import {ActionMenuComponent} from './action-menu.component';
+import {LogIndexFilterComponent} from './log-index-filter.component';
 
-describe('ActionMenuComponent', () => {
-  let component: ActionMenuComponent;
-  let fixture: ComponentFixture<ActionMenuComponent>;
+describe('LogIndexFilterComponent', () => {
+  let component: LogIndexFilterComponent;
+  let fixture: ComponentFixture<LogIndexFilterComponent>;
 
   beforeEach(async(() => {
     const httpClient = {
@@ -57,6 +61,7 @@ describe('ActionMenuComponent', () => {
     };
     TestBed.configureTestingModule({
       imports: [
+        FormsModule,
         ...TranslationModules,
         StoreModule.provideStore({
           auditLogs,
@@ -74,14 +79,19 @@ describe('ActionMenuComponent', () => {
           tabs
         })
       ],
-      declarations: [ActionMenuComponent],
+      declarations: [
+        LogIndexFilterComponent,
+        DropdownButtonComponent,
+        DropdownListComponent
+      ],
       providers: [
+        ComponentGeneratorService,
         {
           provide: HttpClientService,
           useValue: httpClient
         },
-        HistoryManagerService,
         LogsContainerService,
+        UserSettingsService,
         UtilsService,
         AuditLogsService,
         ServiceLogsService,
@@ -103,7 +113,7 @@ describe('ActionMenuComponent', () => {
   }));
 
   beforeEach(() => {
-    fixture = TestBed.createComponent(ActionMenuComponent);
+    fixture = TestBed.createComponent(LogIndexFilterComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
new file mode 100644
index 0000000..a65555f
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
@@ -0,0 +1,177 @@
+/**
+ * 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, OnInit, Output, EventEmitter, forwardRef} from 
'@angular/core';
+import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
+import {Observable} from 'rxjs/Observable';
+import 'rxjs/add/operator/map';
+import {Moment} from 'moment';
+import {ListItem} from '@app/classes/list-item';
+import {HomogeneousObject, LogLevelObject} from '@app/classes/object';
+import {LogIndexFilterComponentConfig} from '@app/classes/settings';
+import {LogLevel} from '@app/classes/string';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {UserSettingsService} from '@app/services/user-settings.service';
+import {UtilsService} from '@app/services/utils.service';
+import {ClustersService} from '@app/services/storage/clusters.service';
+import {HostsService} from '@app/services/storage/hosts.service';
+
+@Component({
+  selector: 'log-index-filter',
+  templateUrl: './log-index-filter.component.html',
+  styleUrls: ['./log-index-filter.component.less'],
+  providers: [
+    {
+      provide: NG_VALUE_ACCESSOR,
+      useExisting: forwardRef(() => LogIndexFilterComponent),
+      multi: true
+    }
+  ]
+})
+export class LogIndexFilterComponent implements OnInit, ControlValueAccessor {
+
+  constructor(
+    private logsContainer: LogsContainerService, private settingsService: 
UserSettingsService,
+    private utils: UtilsService, private clustersStorage: ClustersService, 
private hostsStorage: HostsService
+  ) {
+  }
+
+  ngOnInit() {
+    this.changeIsSubmitDisabled.emit(true);
+    this.clusters.subscribe((clusters: string[]) => 
this.settingsService.loadIndexFilterConfig(clusters));
+  }
+
+  @Output()
+  changeIsSubmitDisabled: EventEmitter<boolean> =  new EventEmitter();
+
+  private onChange: (fn: any) => void;
+
+  readonly columns: LogLevelObject[] = this.logsContainer.logLevels;
+
+  readonly levelNames: LogLevel[] = this.columns.map((level: LogLevelObject): 
LogLevel => level.name);
+
+  clusters: Observable<string[]> = this.clustersStorage.getAll();
+
+  hosts: Observable<string[]> = this.hostsStorage.getAll();
+
+  clustersListItems: Observable<ListItem[]> = this.clusters.map((clusterNames: 
string[]): ListItem[] => {
+    return clusterNames.map(this.utils.getListItemFromString);
+  });
+
+  activeClusterName: string = '';
+
+  /**
+   * Configs for all clusters
+   */
+  private configs: HomogeneousObject<LogIndexFilterComponentConfig[]>;
+
+  /**
+   * Configs for selected cluster
+   * @returns {LogIndexFilterComponentConfig[]}
+   */
+  get activeClusterConfigs(): LogIndexFilterComponentConfig[] {
+    return this.configs[this.activeClusterName];
+  }
+
+  /**
+   * Select or unselect checkboxes for all log levels for given component
+   * @param {string} componentName
+   * @param {boolean} isChecked
+   * @param {boolean} isOverride - indicates whether levels for override are 
processed
+   */
+  processAllLevelsForComponent(componentName: string, isChecked: boolean, 
isOverride: boolean = false): void {
+    const componentConfig = this.getComponentConfigs(componentName),
+      key = isOverride ? 'overrides' : 'defaults';
+    this.levelNames.forEach((levelName: LogLevel) => 
componentConfig[levelName][key] = isChecked);
+    this.updateValue();
+  }
+
+  /**
+   * Select or unselect checkboxes for all components for given log level
+   * @param {LogLevel} levelName
+   * @param {boolean} isChecked
+   */
+  processAllComponentsForLevel(levelName: LogLevel, isChecked: boolean): void {
+    this.activeClusterConfigs.forEach((component: 
LogIndexFilterComponentConfig): void => {
+      component[levelName].defaults = isChecked;
+      component[levelName].overrides = isChecked;
+    });
+    this.updateValue();
+  }
+
+  /**
+   * Indicates whether all log levels for given component are checked
+   * @param {string} componentName
+   * @param {string} isOverride - indicates whether levels for override are 
overviewed
+   * @returns {boolean}
+   */
+  isAllLevelsCheckedForComponent(componentName: string, isOverride: boolean = 
false): boolean {
+    const componentConfig = this.getComponentConfigs(componentName),
+      key = isOverride ? 'overrides' : 'defaults';
+    return this.levelNames.every((levelName: LogLevel): boolean => 
componentConfig[levelName][key]);
+  }
+
+  /**
+   * Indicates whether all components for given log level are checked
+   * @param {LogLevel} levelName
+   * @returns {boolean}
+   */
+  isAllComponentsCheckedForLevel(levelName: LogLevel): boolean {
+    return this.activeClusterConfigs.every((component: 
LogIndexFilterComponentConfig): boolean => {
+      return component[levelName].defaults;
+    });
+  }
+
+  setActiveCluster(clusterName: string): void {
+    this.activeClusterName = clusterName;
+    this.changeIsSubmitDisabled.emit(false);
+  }
+
+  getCheckBoxId(componentName: string, levelName: string, isOverride: boolean 
= false): string {
+    return `component_${componentName}_level_${levelName}${isOverride ? 
'_override' : ''}`;
+  }
+
+  setExpiryTime(time: Moment, componentConfig): void {
+    componentConfig.expiryTime = time.toISOString();
+  }
+
+  private getComponentConfigs(componentName: string) {
+    return this.activeClusterConfigs.find((component: 
LogIndexFilterComponentConfig): boolean => {
+      return component.name === componentName;
+    });
+  }
+
+  writeValue(filters: HomogeneousObject<LogIndexFilterComponentConfig[]>): 
void {
+    this.configs = filters;
+    this.updateValue();
+  }
+
+  registerOnChange(callback: any): void {
+    this.onChange = callback;
+  }
+
+  registerOnTouched(): void {
+  }
+
+  updateValue(): void {
+    if(this.onChange) {
+      this.onChange(this.configs);
+    }
+  }
+
+}
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 d853bb5..e8ccc08 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
@@ -30,8 +30,8 @@ import {Tab} from '@app/classes/models/tab';
 import {BarGraph} from '@app/classes/models/bar-graph';
 import {ActiveServiceLogEntry} from '@app/classes/active-service-log-entry';
 import {ListItem} from '@app/classes/list-item';
-import {HomogeneousObject} from '@app/classes/object';
-import {LogsType} from '@app/classes/string';
+import {HomogeneousObject, LogLevelObject} from '@app/classes/object';
+import {LogsType, LogLevel} from '@app/classes/string';
 import {FiltersPanelComponent} from 
"@app/components/filters-panel/filters-panel.component";
 
 @Component({
@@ -52,7 +52,11 @@ export class LogsContainerComponent implements OnInit {
     this.logsContainer.loadColumnsNames();
     this.appState.getParameter('activeLogsType').subscribe((value: LogsType) 
=> this.logsType = value);
     this.serviceLogsHistogramStorage.getAll().subscribe((data: BarGraph[]): 
void => {
-      this.serviceLogsHistogramData = this.logsContainer.getGraphData(data, 
Object.keys(this.logsContainer.colors));
+      this.serviceLogsHistogramData = this.logsContainer.getGraphData(data, 
this.logsContainer.logLevels.map((
+        level: LogLevelObject
+      ): LogLevel => {
+        return level.name;
+      }));
     });
     this.auditLogsGraphStorage.getAll().subscribe((data: BarGraph[]): void => {
       this.auditLogsGraphData = this.logsContainer.getGraphData(data);
@@ -88,9 +92,13 @@ export class LogsContainerComponent implements OnInit {
 
   auditLogsGraphData: HomogeneousObject<HomogeneousObject<number>>;
 
-  get serviceLogsHistogramColors(): HomogeneousObject<string> {
-    return this.logsContainer.colors;
-  }
+  serviceLogsHistogramColors: HomogeneousObject<string> = 
this.logsContainer.logLevels.reduce((
+    currentObject: HomogeneousObject<string>, level: LogLevelObject
+  ): HomogeneousObject<string> => {
+    return Object.assign({}, currentObject, {
+      [level.name]: level.color
+    });
+  }, {});
 
   get autoRefreshRemainingSeconds(): number {
     return this.logsContainer.autoRefreshRemainingSeconds;
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.html
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.html
index 398a429..799b840 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.html
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.html
@@ -17,7 +17,9 @@
 
 <div class="modal-backdrop in"></div>
 <div class="modal in">
-  <div [ngClass]="{'modal-dialog': true, 'modal-sm': isSmallModal, 'modal-lg': 
isLargeModal}">
+  <div [ngClass]="{
+    'modal-dialog': true, 'modal-sm': isSmallModal, 'modal-lg': isLargeModal, 
'modal-xl': isExtraLargeModal
+  }">
     <div class="modal-content">
       <div *ngIf="showHeader" class="modal-header">
         <button *ngIf="showCloseButton" type="button" class="close" 
data-dismiss="modal" (click)="onClose()">
@@ -33,6 +35,7 @@
         <button *ngIf="showCancelButton" class="btn {{cancelButtonClassName}}"
                 (click)="onCancel()">{{cancelButtonLabel | translate}}</button>
         <button *ngIf="showSubmitButton" class="btn {{submitButtonClassName}}"
+                [attr.disabled]="isSubmitDisabled ? 'disabled' : null"
                 (click)="onSubmit()">{{submitButtonLabel | translate}}</button>
       </div>
     </div>
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.less
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.less
new file mode 100644
index 0000000..9d1d642
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.less
@@ -0,0 +1,22 @@
+/**
+ * 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 '../variables';
+
+.modal-xl {
+  width: @large-modal-width;
+}
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.ts
index a5df53f..a724086 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/modal/modal.component.ts
@@ -21,7 +21,8 @@ import * as $ from 'jquery';
 
 @Component({
   selector: 'modal',
-  templateUrl: './modal.component.html'
+  templateUrl: './modal.component.html',
+  styleUrls: ['./modal.component.less']
 })
 export class ModalComponent implements OnInit, AfterViewInit {
 
@@ -81,6 +82,12 @@ export class ModalComponent implements OnInit, AfterViewInit 
{
   @Input()
   isLargeModal: boolean = false;
 
+  @Input()
+  isExtraLargeModal: boolean = false;
+
+  @Input()
+  isSubmitDisabled: boolean = false;
+
   @ContentChild(TemplateRef)
   bodyTemplate;
 
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
index 27fafe5..61a479e 100644
--- 
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
@@ -192,7 +192,7 @@
     .log-list {
       color: @base-font-color;
       border-bottom: 1px solid @log-list-border-color;
-      font-size: @log-list-font-size;
+      font-size: @table-font-size;
       .log-date-row {
         background: @list-header-background-color;
         padding: @log-list-row-data-padding;
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 3d79b46..b522562 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
@@ -36,6 +36,8 @@ import {ServiceLogsTruncatedService, serviceLogsTruncated} 
from '@app/services/s
 import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
+import {UserSettingsService} from '@app/services/user-settings.service';
+import {UtilsService} from '@app/services/utils.service';
 import {AuthService} from '@app/services/auth.service';
 import {TimeZoneAbbrPipe} from '@app/pipes/timezone-abbr.pipe';
 import {ModalComponent} from '@app/components/modal/modal.component';
@@ -98,7 +100,9 @@ describe('TimeZonePickerComponent', () => {
           useValue: httpClient
         },
         LogsContainerService,
-        AuthService
+        AuthService,
+        UserSettingsService,
+        UtilsService
       ],
     })
     .compileComponents();
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.ts
index 98758ab..a8a3480 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.ts
@@ -20,6 +20,7 @@ import {Component, OnInit} from '@angular/core';
 import * as $ from 'jquery';
 import '@vendor/js/WorldMapGenerator.min';
 import {AppSettingsService} from '@app/services/storage/app-settings.service';
+import {UserSettingsService} from '@app/services/user-settings.service';
 
 @Component({
   selector: 'timezone-picker',
@@ -28,7 +29,7 @@ import {AppSettingsService} from 
'@app/services/storage/app-settings.service';
 })
 export class TimeZonePickerComponent implements OnInit {
 
-  constructor(private appSettings: AppSettingsService) {
+  constructor(private appSettings: AppSettingsService, private 
settingsService: UserSettingsService) {
   }
 
   ngOnInit() {
@@ -72,10 +73,7 @@ export class TimeZonePickerComponent implements OnInit {
 
   setTimeZone(): void {
     const timeZone = this.timeZoneSelect.val();
-
-    // TODO replace with setTimeZone() method call from settings service as 
soon as it's implemented
-    this.appSettings.setParameter('timeZone', timeZone);
-
+    this.settingsService.setTimeZone(timeZone);
     this.setTimeZonePickerDisplay(false);
   }
 
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 f26f5ca..6f403a5 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less
@@ -65,13 +65,16 @@
 
 // Table
 @table-border-color: #EEE;
+@table-font-size: 13px;
 
 // Graph
 @graph-padding: .5rem;
 
 // Log list
 @log-list-row-data-padding: 8px;
-@log-list-font-size: 13px;
 @log-list-row-hover-background-color: #E7F6FC;
 @log-list-row-hover-border-color: #A7DFF2;
 @log-list-border-color: rgb(238, 238, 238);
+
+// Modals
+@large-modal-width: 1200px;
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 1e1246b..fd4270b 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
@@ -1068,63 +1068,1437 @@ export const mockData = {
           configurationUploaded: true
         }
       },
-      userconfig: {
-        userConfigList: [
-          {
-            id: 'c0',
-            userName: 'admin',
-            filtername: 'service',
-            values: 'hdfs',
-            shareNameList: [
-              's0',
-              's1'
-            ],
-            rowType: 'history'
-          },
-          {
-            id: 'c0',
-            userName: 'user',
-            filtername: 'component',
-            values: 'namenode',
-            shareNameList: [
-              's2',
-              's3'
-            ],
-            rowType: 'history'
-          }
-        ],
+      shipper: {
         filters: {
-          filter0: {
-            label: 'filter0',
-            hosts: [
-              'h0',
-              'h1'
-            ],
-            defaultLevels: [
-              'l0',
-              'l1'
-            ],
-            overrideLevels: [
-              'l2',
-              'l3'
-            ],
-            expiryTime: '2017-05-29T11:30:22.531Z'
+          cl0: {
+            level: {
+              filter: {
+                ambari_agent: {
+                  label: 'ambari_agent',
+                  hosts: [
+                    'h0'
+                  ],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [
+                    'FATAL'
+                  ],
+                  expiryTime: currentTime.clone().add(1, 'd').toISOString()
+                },
+                ambari_alerts: {
+                  label: 'ambari_alerts',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_audit: {
+                  label: 'ambari_audit',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_config_changes: {
+                  label: 'ambari_config_changes',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_eclipselink: {
+                  label: 'ambari_eclipselink',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server: {
+                  label: 'ambari_server',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server_check_database: {
+                  label: 'ambari_server_check_database',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_collector: {
+                  label: 'ams_collector',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_grafana: {
+                  label: 'ams_grafana',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_master: {
+                  label: 'ams_hbase_master',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_regionserver: {
+                  label: 'ams_hbase_regionserver',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_monitor: {
+                  label: 'ams_monitor',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_datanode: {
+                  label: 'hdfs_datanode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_journalnode: {
+                  label: 'hdfs_journalnode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_namenode: {
+                  label: 'hdfs_namenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_nfs3: {
+                  label: 'hdfs_nfs3',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_secondarynamenode: {
+                  label: 'hdfs_secondarynamenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_zkfc: {
+                  label: 'hdfs_zkfc',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                infra_solr: {
+                  label: 'infra_solr',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_app: {
+                  label: 'logsearch_app',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_feeder: {
+                  label: 'logsearch_feeder',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_perf: {
+                  label: 'logsearch_perf',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                zookeeper: {
+                  label: 'zookeeper',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                }
+              }
+            }
           },
-          filter1: {
-            label: 'filter1',
-            hosts: [
-              'h1',
-              'h2'
-            ],
-            defaultLevels: [
-              'l4',
-              'l5'
-            ],
-            overrideLevels: [
-              'l6',
-              'l7'
-            ],
-            expiryTime: '2017-05-30T11:30:22.531Z'
+          cl1: {
+            level: {
+              filter: {
+                ambari_agent: {
+                  label: 'ambari_agent',
+                  hosts: [
+                    'h0'
+                  ],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [
+                    'FATAL'
+                  ],
+                  expiryTime: currentTime.clone().add(1, 'd').toISOString()
+                },
+                ambari_alerts: {
+                  label: 'ambari_alerts',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_audit: {
+                  label: 'ambari_audit',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_config_changes: {
+                  label: 'ambari_config_changes',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_eclipselink: {
+                  label: 'ambari_eclipselink',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server: {
+                  label: 'ambari_server',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server_check_database: {
+                  label: 'ambari_server_check_database',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_collector: {
+                  label: 'ams_collector',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_grafana: {
+                  label: 'ams_grafana',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_master: {
+                  label: 'ams_hbase_master',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_regionserver: {
+                  label: 'ams_hbase_regionserver',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_monitor: {
+                  label: 'ams_monitor',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_datanode: {
+                  label: 'hdfs_datanode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_journalnode: {
+                  label: 'hdfs_journalnode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_namenode: {
+                  label: 'hdfs_namenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_nfs3: {
+                  label: 'hdfs_nfs3',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_secondarynamenode: {
+                  label: 'hdfs_secondarynamenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_zkfc: {
+                  label: 'hdfs_zkfc',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                infra_solr: {
+                  label: 'infra_solr',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_app: {
+                  label: 'logsearch_app',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_feeder: {
+                  label: 'logsearch_feeder',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_perf: {
+                  label: 'logsearch_perf',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                zookeeper: {
+                  label: 'zookeeper',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                }
+              }
+            }
+          },
+          cl2: {
+            level: {
+              filter: {
+                ambari_agent: {
+                  label: 'ambari_agent',
+                  hosts: [
+                    'h0'
+                  ],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [
+                    'FATAL'
+                  ],
+                  expiryTime: currentTime.clone().add(1, 'd').toISOString()
+                },
+                ambari_alerts: {
+                  label: 'ambari_alerts',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_audit: {
+                  label: 'ambari_audit',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_config_changes: {
+                  label: 'ambari_config_changes',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_eclipselink: {
+                  label: 'ambari_eclipselink',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server: {
+                  label: 'ambari_server',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server_check_database: {
+                  label: 'ambari_server_check_database',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_collector: {
+                  label: 'ams_collector',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_grafana: {
+                  label: 'ams_grafana',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_master: {
+                  label: 'ams_hbase_master',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_regionserver: {
+                  label: 'ams_hbase_regionserver',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_monitor: {
+                  label: 'ams_monitor',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_datanode: {
+                  label: 'hdfs_datanode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_journalnode: {
+                  label: 'hdfs_journalnode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_namenode: {
+                  label: 'hdfs_namenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_nfs3: {
+                  label: 'hdfs_nfs3',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_secondarynamenode: {
+                  label: 'hdfs_secondarynamenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_zkfc: {
+                  label: 'hdfs_zkfc',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                infra_solr: {
+                  label: 'infra_solr',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_app: {
+                  label: 'logsearch_app',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_feeder: {
+                  label: 'logsearch_feeder',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_perf: {
+                  label: 'logsearch_perf',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                zookeeper: {
+                  label: 'zookeeper',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                }
+              }
+            }
+          },
+          cl3: {
+            level: {
+              filter: {
+                ambari_agent: {
+                  label: 'ambari_agent',
+                  hosts: [
+                    'h0'
+                  ],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [
+                    'FATAL'
+                  ],
+                  expiryTime: currentTime.clone().add(1, 'd').toISOString()
+                },
+                ambari_alerts: {
+                  label: 'ambari_alerts',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_audit: {
+                  label: 'ambari_audit',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_config_changes: {
+                  label: 'ambari_config_changes',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_eclipselink: {
+                  label: 'ambari_eclipselink',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server: {
+                  label: 'ambari_server',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server_check_database: {
+                  label: 'ambari_server_check_database',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_collector: {
+                  label: 'ams_collector',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_grafana: {
+                  label: 'ams_grafana',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_master: {
+                  label: 'ams_hbase_master',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_regionserver: {
+                  label: 'ams_hbase_regionserver',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_monitor: {
+                  label: 'ams_monitor',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_datanode: {
+                  label: 'hdfs_datanode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_journalnode: {
+                  label: 'hdfs_journalnode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_namenode: {
+                  label: 'hdfs_namenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_nfs3: {
+                  label: 'hdfs_nfs3',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_secondarynamenode: {
+                  label: 'hdfs_secondarynamenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_zkfc: {
+                  label: 'hdfs_zkfc',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                infra_solr: {
+                  label: 'infra_solr',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_app: {
+                  label: 'logsearch_app',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_feeder: {
+                  label: 'logsearch_feeder',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_perf: {
+                  label: 'logsearch_perf',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                zookeeper: {
+                  label: 'zookeeper',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                }
+              }
+            }
+          },
+          cl4: {
+            level: {
+              filter: {
+                ambari_agent: {
+                  label: 'ambari_agent',
+                  hosts: [
+                    'h0'
+                  ],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [
+                    'FATAL'
+                  ],
+                  expiryTime: currentTime.clone().add(1, 'd').toISOString()
+                },
+                ambari_alerts: {
+                  label: 'ambari_alerts',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_audit: {
+                  label: 'ambari_audit',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_config_changes: {
+                  label: 'ambari_config_changes',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_eclipselink: {
+                  label: 'ambari_eclipselink',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server: {
+                  label: 'ambari_server',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ambari_server_check_database: {
+                  label: 'ambari_server_check_database',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_collector: {
+                  label: 'ams_collector',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_grafana: {
+                  label: 'ams_grafana',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_master: {
+                  label: 'ams_hbase_master',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_hbase_regionserver: {
+                  label: 'ams_hbase_regionserver',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                ams_monitor: {
+                  label: 'ams_monitor',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_datanode: {
+                  label: 'hdfs_datanode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_journalnode: {
+                  label: 'hdfs_journalnode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_namenode: {
+                  label: 'hdfs_namenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_nfs3: {
+                  label: 'hdfs_nfs3',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_secondarynamenode: {
+                  label: 'hdfs_secondarynamenode',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                hdfs_zkfc: {
+                  label: 'hdfs_zkfc',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                infra_solr: {
+                  label: 'infra_solr',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_app: {
+                  label: 'logsearch_app',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_feeder: {
+                  label: 'logsearch_feeder',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                logsearch_perf: {
+                  label: 'logsearch_perf',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                },
+                zookeeper: {
+                  label: 'zookeeper',
+                  hosts: [],
+                  defaultLevels: [
+                    'FATAL',
+                    'ERROR',
+                    'WARN',
+                    'INFO'
+                  ],
+                  overrideLevels: [],
+                  expiryTime: null
+                }
+              }
+            }
           }
         },
         names: []
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.ts
index 1f82367..bf06525 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.ts
@@ -22,6 +22,7 @@ import {ComponentsService} from 
'@app/services/storage/components.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {NodeBarComponent} from '@app/components/node-bar/node-bar.component';
 import {HistoryItemControlsComponent} from 
'@app/components/history-item-controls/history-item-controls.component';
+import {LogLevelObject} from '@app/classes/object';
 
 @Injectable()
 export class ComponentGeneratorService {
@@ -29,6 +30,10 @@ export class ComponentGeneratorService {
   constructor(private resolver: ComponentFactoryResolver, private 
hostsStorage: HostsService, private componentsStorage: ComponentsService, 
private logsContainer: LogsContainerService) {
   }
 
+  private get logLevels(): LogLevelObject[] {
+    return this.logsContainer.logLevels;
+  }
+
   private createComponent(type: any, container: ViewContainerRef, properties?: 
any): void {
     const factory = this.resolver.resolveComponentFactory(type);
     container.clear();
@@ -43,7 +48,7 @@ export class ComponentGeneratorService {
         const selectedHost = hosts.find(host => host.name === hostName);
         data = selectedHost.logLevelCount.map(event => {
           return {
-            color: this.logsContainer.colors[event.name],
+            color: this.logLevels.find((level: LogLevelObject): boolean => 
level.name === event.name).color,
             value: event.value
           };
         });
@@ -63,7 +68,7 @@ export class ComponentGeneratorService {
         const selectedHost = components.find(host => host.name === 
componentName);
         data = selectedHost.logLevelCount.map(event => {
           return {
-            color: this.logsContainer.colors[event.name],
+            color: this.logLevels.find((level: LogLevelObject): boolean => 
level.name === event.name).color,
             value: event.value
           };
         });
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.ts
index 1650d90..52f4d5b 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.ts
@@ -82,6 +82,9 @@ export class HttpClientService extends Http {
     topAuditLogsResources: {
       url: variables => `audit/logs/resources/${variables.number}`,
       params: opts => new AuditLogsTopResourcesQueryParams(opts)
+    },
+    logIndexFilters: {
+      url: variables => `shipper/filters/${variables.clusterName}/level`
     }
   };
 
@@ -148,10 +151,14 @@ export class HttpClientService extends Http {
     return req;
   }
 
-  get(url, params?: HomogeneousObject<string>, urlVariables?: 
HomogeneousObject<string>): Observable<Response> {
+  get(url: string, params?: HomogeneousObject<string>, urlVariables?: 
HomogeneousObject<string>): Observable<Response> {
     return super.get(this.generateUrlString(url, urlVariables), 
this.generateOptions(url, params));
   }
 
+  put(url: string, body: any, params?: HomogeneousObject<string>, 
urlVariables?: HomogeneousObject<string>): Observable<Response> {
+    return super.put(this.generateUrlString(url, urlVariables), body, 
this.generateOptions(url, params));
+  }
+
   postFormData(url: string, params: HomogeneousObject<string>, options?: 
RequestOptionsArgs): Observable<Response> {
     const encodedParams = this.generateOptions(url, params).params;
     let body;
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 a8e7c3f..2f83935 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
@@ -36,8 +36,6 @@ import {ServiceLogsTruncatedService, serviceLogsTruncated} 
from '@app/services/s
 import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {UtilsService} from '@app/services/utils.service';
-import {ListItem} from '@app/classes/list-item';
-import {NodeItem} from '@app/classes/models/node-item';
 
 import {LogsContainerService} from './logs-container.service';
 
@@ -98,28 +96,4 @@ describe('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'
-      });
-    }));
-  });
 });
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
index 6a2108b..a523e03 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
@@ -48,7 +48,7 @@ import {
   FilterCondition, TimeUnitListItem, SortingListItem, SearchBoxParameter, 
SearchBoxParameterTriggered
 } from '@app/classes/filtering';
 import {ListItem} from '@app/classes/list-item';
-import {HomogeneousObject} from '@app/classes/object';
+import {HomogeneousObject, LogLevelObject} from '@app/classes/object';
 import {LogsType, ScrollType, SortingType} from '@app/classes/string';
 import {Tab} from '@app/classes/models/tab';
 import {LogField} from '@app/classes/models/log-field';
@@ -126,6 +126,44 @@ export class LogsContainerService {
 
   private readonly paginationOptions: string[] = ['10', '25', '50', '100'];
 
+  readonly logLevels: LogLevelObject[] = [
+    {
+      name: 'FATAL',
+      label: 'levels.fatal',
+      color: '#830A0A'
+    },
+    {
+      name: 'ERROR',
+      label: 'levels.error',
+      color: '#E81D1D'
+    },
+    {
+      name: 'WARN',
+      label: 'levels.warn',
+      color: '#FF8916'
+    },
+    {
+      name: 'INFO',
+      label: 'levels.info',
+      color: '#2577B5'
+    },
+    {
+      name: 'DEBUG',
+      label: 'levels.debug',
+      color: '#65E8FF'
+    },
+    {
+      name: 'TRACE',
+      label: 'levels.trace',
+      color: '#888'
+    },
+    {
+      name: 'UNKNOWN',
+      label: 'levels.unknown',
+      color: '#BDBDBD'
+    }
+  ];
+
   filters: HomogeneousObject<FilterCondition> = {
     clusters: {
       label: 'filter.clusters',
@@ -365,36 +403,12 @@ export class LogsContainerService {
     levels: {
       label: 'filter.levels',
       iconClass: 'fa fa-sort-amount-asc',
-      options: [
-        {
-          label: 'levels.fatal',
-          value: 'FATAL'
-        },
-        {
-          label: 'levels.error',
-          value: 'ERROR'
-        },
-        {
-          label: 'levels.warn',
-          value: 'WARN'
-        },
-        {
-          label: 'levels.info',
-          value: 'INFO'
-        },
-        {
-          label: 'levels.debug',
-          value: 'DEBUG'
-        },
-        {
-          label: 'levels.trace',
-          value: 'TRACE'
-        },
-        {
-          label: 'levels.unknown',
-          value: 'UNKNOWN'
-        }
-      ],
+      options: this.logLevels.map((level: LogLevelObject): ListItem => {
+        return {
+          label: level.label,
+          value: level.name
+        };
+      }),
       defaultSelection: [],
       fieldName: 'level'
     },
@@ -487,16 +501,6 @@ export class LogsContainerService {
     }
   };
 
-  readonly colors = {
-    FATAL: '#830A0A',
-    ERROR: '#E81D1D',
-    WARN: '#FF8916',
-    INFO: '#2577B5',
-    DEBUG: '#65E8FF',
-    TRACE: '#888',
-    UNKNOWN: '#BDBDBD'
-  };
-
   private readonly filtersMapping = {
     clusters: ['clusters'],
     timeRange: ['to', 'from'],
@@ -616,30 +620,6 @@ export class LogsContainerService {
 
   auditLogs: Observable<AuditLog[]> = 
Observable.combineLatest(this.auditLogsStorage.getAll(), 
this.auditLogsColumns).map(this.logsMapper);
 
-  /**
-   * 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 NodeItem object
-   * @param node {NodeItem}
-   * @returns {ListItem}
-   */
-  private getListItemFromNode(node: NodeItem): ListItem {
-    return {
-      label: `${node.name} (${node.value})`,
-      value: node.name
-    };
-  }
-
   queryParameterNameChange: Subject<SearchBoxParameterTriggered> = new 
Subject();
 
   queryParameterAdd: Subject<SearchBoxParameter> = new Subject();
@@ -976,7 +956,7 @@ export class LogsContainerService {
     request.subscribe((response: Response): void => {
       const clusterNames = response.json();
       if (clusterNames) {
-        
this.filters.clusters.options.push(...clusterNames.map(this.getListItemFromString));
+        
this.filters.clusters.options.push(...clusterNames.map(this.utils.getListItemFromString));
         this.clustersStorage.addInstances(clusterNames);
       }
     });
@@ -993,7 +973,7 @@ export class LogsContainerService {
             }, 0)
           }));
       if (components) {
-        
this.filters.components.options.push(...components.map(this.getListItemFromNode));
+        
this.filters.components.options.push(...components.map(this.utils.getListItemFromNode));
         this.componentsStorage.addInstances(components);
       }
     });
@@ -1006,7 +986,7 @@ export class LogsContainerService {
       const jsonResponse = response.json(),
         hosts = jsonResponse && jsonResponse.vNodeList;
       if (hosts) {
-        
this.filters.hosts.options.push(...hosts.map(this.getListItemFromNode));
+        
this.filters.hosts.options.push(...hosts.map(this.utils.getListItemFromNode));
         this.hostsStorage.addInstances(hosts);
       }
     });
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
index 3f54625..38085f8 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
@@ -22,7 +22,6 @@ import {appState} from 
'@app/services/storage/app-state.service';
 import {auditLogs} from '@app/services/storage/audit-logs.service';
 import {clusters} from '@app/services/storage/clusters.service';
 import {components} from '@app/services/storage/components.service';
-import {filters} from '@app/services/storage/filters.service';
 import {graphs} from '@app/services/storage/graphs.service';
 import {hosts} from '@app/services/storage/hosts.service';
 import {serviceLogs} from '@app/services/storage/service-logs.service';
@@ -45,7 +44,6 @@ export const reducers = {
   graphs,
   hosts,
   userConfigs,
-  filters,
   clusters,
   components,
   serviceLogsFields,
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.spec.ts
similarity index 79%
copy from 
ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
copy to 
ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.spec.ts
index ba53ee1..33c0459 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.spec.ts
@@ -16,9 +16,7 @@
  * limitations under the License.
  */
 
-import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
-import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-import {TranslationModules} from '@app/test-config.spec';
+import {TestBed, inject} from '@angular/core/testing';
 import {StoreModule} from '@ngrx/store';
 import {AuditLogsService, auditLogs} from 
'@app/services/storage/audit-logs.service';
 import {ServiceLogsService, serviceLogs} from 
'@app/services/storage/service-logs.service';
@@ -35,18 +33,14 @@ import {ComponentsService, components} from 
'@app/services/storage/components.se
 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 {HistoryManagerService} from '@app/services/history-manager.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {UtilsService} from '@app/services/utils.service';
 
-import {ActionMenuComponent} from './action-menu.component';
+import {UserSettingsService} from './user-settings.service';
 
-describe('ActionMenuComponent', () => {
-  let component: ActionMenuComponent;
-  let fixture: ComponentFixture<ActionMenuComponent>;
-
-  beforeEach(async(() => {
+describe('UserSettingsService', () => {
+  beforeEach(() => {
     const httpClient = {
       get: () => {
         return {
@@ -57,7 +51,6 @@ describe('ActionMenuComponent', () => {
     };
     TestBed.configureTestingModule({
       imports: [
-        ...TranslationModules,
         StoreModule.provideStore({
           auditLogs,
           serviceLogs,
@@ -74,13 +67,12 @@ describe('ActionMenuComponent', () => {
           tabs
         })
       ],
-      declarations: [ActionMenuComponent],
       providers: [
+        UserSettingsService,
         {
           provide: HttpClientService,
           useValue: httpClient
         },
-        HistoryManagerService,
         LogsContainerService,
         UtilsService,
         AuditLogsService,
@@ -96,19 +88,11 @@ describe('ActionMenuComponent', () => {
         HostsService,
         ServiceLogsTruncatedService,
         TabsService
-      ],
-      schemas: [CUSTOM_ELEMENTS_SCHEMA]
-    })
-    .compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(ActionMenuComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
+      ]
+    });
   });
 
-  it('should create component', () => {
-    expect(component).toBeTruthy();
-  });
+  it('should be created', inject([UserSettingsService], (service: 
UserSettingsService) => {
+    expect(service).toBeTruthy();
+  }));
 });
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.ts
 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.ts
new file mode 100644
index 0000000..5992809
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.ts
@@ -0,0 +1,162 @@
+/**
+ * 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 {FormGroup, FormControl} from '@angular/forms';
+import {Response} from '@angular/http';
+import {HomogeneousObject, LogLevelObject} from '@app/classes/object';
+import {LevelOverridesConfig, LogIndexFilterComponentConfig} from 
'@app/classes/settings';
+import {LogLevel} from '@app/classes/string';
+import {Filter} from '@app/classes/models/filter';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {HttpClientService} from '@app/services/http-client.service';
+import {UtilsService} from '@app/services/utils.service';
+import {AppSettingsService} from '@app/services/storage/app-settings.service';
+
+@Injectable()
+export class UserSettingsService {
+
+  constructor(private logsContainer: LogsContainerService, private httpClient: 
HttpClientService,
+              private utils: UtilsService, private settingsStorage: 
AppSettingsService) {
+    settingsStorage.getParameter('logIndexFilters').subscribe((filters: 
HomogeneousObject<HomogeneousObject<Filter>>): void => {
+      const configs = this.parseLogIndexFilterObjects(filters);
+      this.settingsFormGroup.controls.logIndexFilter.setValue(configs);
+    });
+  }
+
+  settingsFormGroup: FormGroup = new FormGroup({
+    logIndexFilter: new FormControl()
+  });
+
+  currentValues = {
+    logIndexFilter: {}
+  };
+
+  readonly levelNames = this.logsContainer.logLevels.map((level: 
LogLevelObject): LogLevel => level.name);
+
+  loadIndexFilterConfig(clusterNames: string[]): void {
+    let processedRequests: number = 0,
+      allFilters: HomogeneousObject<Filter> = {},
+      totalCount = clusterNames.length;
+    clusterNames.forEach((clusterName: string): void => {
+      this.httpClient.get('logIndexFilters', null, {
+        clusterName
+      }).subscribe((response: Response): void => {
+        const filters = response.json() && response.json().filter;
+        if (filters) {
+          Object.assign(allFilters, {
+            [clusterName]: filters
+          });
+          if (++processedRequests === totalCount) {
+            this.settingsStorage.setParameter('logIndexFilters', allFilters);
+            this.currentValues.logIndexFilter = allFilters;
+          }
+        }
+      });
+    });
+  }
+
+  saveIndexFilterConfig(): void {
+    const savedValue = this.currentValues.logIndexFilter,
+      newValue = this.settingsFormGroup.controls.logIndexFilter.value,
+      clusters = Object.keys(newValue);
+    let storedValue = {};
+    clusters.forEach((clusterName: string): void => {
+      const savedConfig = savedValue[clusterName],
+        newConfig = this.getLogIndexFilterObject(newValue[clusterName]);
+      Object.assign(storedValue, {
+        [clusterName]: newConfig
+      });
+      if (!this.utils.isEqual(savedConfig, newConfig)) {
+        this.httpClient.put('logIndexFilters', {
+          filter: newConfig
+        }, null, {
+          clusterName
+        });
+      }
+    });
+    this.settingsStorage.setParameter('logIndexFilters', storedValue);
+  }
+
+  /**
+   * Convert log index filter data for usage in component
+   * @param {HomogeneousObject<HomogeneousObject<Filter>>} filters
+   * @returns {HomogeneousObject<LogIndexFilterComponentConfig[]>}
+   */
+  parseLogIndexFilterObjects(
+    filters: HomogeneousObject<HomogeneousObject<Filter>>
+  ): HomogeneousObject<LogIndexFilterComponentConfig[]> {
+    const levels = this.levelNames;
+    return filters ? Object.keys(filters).reduce((
+      clustersCurrent: HomogeneousObject<LogIndexFilterComponentConfig[]>, 
clusterName: string
+    ): HomogeneousObject<LogIndexFilterComponentConfig[]> => {
+      const clusterConfigs = filters[clusterName],
+        clusterParsedObject = Object.keys(clusterConfigs).map((componentName: 
string) => {
+          const componentConfigs = clusterConfigs[componentName],
+            levelProperties = levels.reduce((
+              levelsCurrent: HomogeneousObject<LevelOverridesConfig>, 
levelName: LogLevel
+            ): LevelOverridesConfig => {
+              return Object.assign({}, levelsCurrent, {
+                [levelName]: {
+                  defaults: componentConfigs.defaultLevels.indexOf(levelName) 
> -1,
+                  overrides: 
componentConfigs.overrideLevels.indexOf(levelName) > -1
+                }
+              });
+            }, {});
+          return Object.assign({
+            name: componentName,
+            label: componentConfigs.label,
+            hasOverrides: false,
+            hosts: componentConfigs.hosts.join(),
+            expiryTime: componentConfigs.expiryTime
+          }, levelProperties);
+        });
+      return Object.assign({}, clustersCurrent, {
+        [clusterName]: clusterParsedObject
+      });
+    }, {}) : {};
+  }
+
+  /**
+   * Convert data from log index filter component to format for PUT API call
+   * @param configs
+   * @returns {HomogeneousObject<Filter>}
+   */
+  private getLogIndexFilterObject(configs): HomogeneousObject<Filter> {
+    const levelNames = this.levelNames;
+    return configs.reduce((
+      currentObject: HomogeneousObject<Filter>, componentConfig: 
LogIndexFilterComponentConfig
+    ): HomogeneousObject<Filter> => {
+      const hosts = componentConfig.hosts;
+      return Object.assign({}, currentObject, {
+        [componentConfig.name]: {
+          defaultLevels: levelNames.filter((levelName: LogLevel): boolean => 
componentConfig[levelName].defaults),
+          expiryTime: componentConfig.expiryTime,
+          hosts: hosts ? hosts.split(',') : [],
+          label: componentConfig.label,
+          overrideLevels: levelNames.filter((levelName: LogLevel): boolean => 
componentConfig[levelName].overrides)
+        }
+      });
+    }, {});
+  }
+
+  setTimeZone(timeZone: string): void {
+    this.settingsStorage.setParameter('timeZone', timeZone);
+  }
+
+}
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
index f89462d..861e5c3 100644
--- 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
+++ 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
@@ -417,4 +417,28 @@ describe('UtilsService', () => {
       }));
     });
   });
+
+  describe('#getListItemFromString()', () => {
+    it('should convert string to ListItem', inject([UtilsService], (service: 
UtilsService) => {
+      expect(service.getListItemFromString('customName')).toEqual({
+        label: 'customName',
+        value: 'customName'
+      });
+    }));
+  });
+
+  describe('#getListItemFromNode()', () => {
+    it('should convert NodeItem to ListItem', inject([UtilsService], (service: 
UtilsService) => {
+      expect(service.getListItemFromNode({
+        name: 'customName',
+        value: '1',
+        isParent: true,
+        isRoot: true
+      })).toEqual({
+        label: 'customName (1)',
+        value: 'customName'
+      });
+    }));
+  });
+
 });
diff --git 
a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts 
b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
index 514837c..952a1d1 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
@@ -18,7 +18,9 @@
 
 import {Injectable} from '@angular/core';
 import * as moment from 'moment-timezone';
+import {ListItem} from '@app/classes/list-item';
 import {HomogeneousObject} from '@app/classes/object';
+import {NodeItem} from '@app/classes/models/node-item';
 
 @Injectable()
 export class UtilsService {
@@ -105,4 +107,28 @@ export class UtilsService {
     }, 0);
   }
 
+  /**
+   * Get instance for dropdown list from string
+   * @param name {string}
+   * @returns {ListItem}
+   */
+  getListItemFromString(name: string): ListItem {
+    return {
+      label: name,
+      value: name
+    };
+  }
+
+  /**
+   * Get instance for dropdown list from NodeItem object
+   * @param node {NodeItem}
+   * @returns {ListItem}
+   */
+  getListItemFromNode(node: NodeItem): ListItem {
+    return {
+      label: `${node.name} (${node.value})`,
+      value: node.name
+    };
+  }
+
 }
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 1d8f6c4..7f16078 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
+++ b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
@@ -12,6 +12,7 @@
   "modal.cancel": "Cancel",
   "modal.apply": "Apply",
   "modal.close": "Close",
+  "modal.save": "Save",
 
   "authorization.logout": "Logout",
   "authorization.name": "Username",
@@ -23,6 +24,7 @@
   "topMenu.redo": "Redo",
   "topMenu.refresh": "Refresh",
   "topMenu.history": "History",
+  "topMenu.filter": "Filter",
 
   "filter.all": "All",
 
@@ -183,5 +185,14 @@
   "histogram.gap.day": "day",
   "histogram.gap.days": "days",
   "histogram.gap.week": "week",
-  "histogram.gap.weeks": "weeks"
+  "histogram.gap.weeks": "weeks",
+
+  "logIndexFilter.title": "Log Index Filter",
+  "logIndexFilter.caption": "For each cluster, choose the components, hosts 
and log levels that will be indexed in the log feeder",
+  "logIndexFilter.select": "Select",
+  "logIndexFilter.selectCluster": "Select Cluster",
+  "logIndexFilter.override": "Override Hosts",
+  "logIndexFilter.addHosts": "Add Hosts",
+  "logIndexFilter.hostname": "Hostname",
+  "logIndexFilter.expiryDate": "Expiry Date"
 }

-- 
To stop receiving notification emails like this one, please contact
ababiic...@apache.org.

Reply via email to