You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/10/19 20:10:32 UTC

[09/12] ambari git commit: AMBARI-22269 Log Search UI: provide navigation between Service and Audit Logs. (ababiichuk)

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
index fc0f6ae..af4933a 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
@@ -20,6 +20,8 @@ import {Component, OnInit, Input, forwardRef} from '@angular/core';
 import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
 import {Moment} from 'moment';
 import {FilteringService} from '@app/services/filtering.service';
+import {ListItem} from '@app/classes/list-item';
+import {TimeUnitListItem} from '@app/classes/filtering';
 
 @Component({
   selector: 'time-range-picker',
@@ -53,7 +55,7 @@ export class TimeRangePickerComponent implements OnInit, ControlValueAccessor {
 
   private onChange: (fn: any) => void;
 
-  get quickRanges(): any[][] {
+  get quickRanges(): (ListItem | TimeUnitListItem[])[] {
     return this.filtering.filters.timeRange.options;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
index 7105624..53afc47 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
@@ -30,6 +30,7 @@ import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-log
 import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
 import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
 import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {ComponentActionsService} from '@app/services/component-actions.service';
 import {FilteringService} from '@app/services/filtering.service';
 import {HttpClientService} from '@app/services/http-client.service';
@@ -44,6 +45,14 @@ describe('TimeZonePickerComponent', () => {
   let fixture: ComponentFixture<TimeZonePickerComponent>;
 
   beforeEach(async(() => {
+    const httpClient = {
+      get: () => {
+        return {
+          subscribe: () => {
+          }
+        }
+      }
+    };
     TestBed.configureTestingModule({
       declarations: [
         TimeZonePickerComponent,
@@ -62,7 +71,8 @@ describe('TimeZonePickerComponent', () => {
           serviceLogs,
           serviceLogsFields,
           serviceLogsHistogramData,
-          serviceLogsTruncated
+          serviceLogsTruncated,
+          tabs
         }),
         ...TranslationModules
       ],
@@ -78,9 +88,13 @@ describe('TimeZonePickerComponent', () => {
         ServiceLogsFieldsService,
         ServiceLogsHistogramDataService,
         ServiceLogsTruncatedService,
+        TabsService,
         ComponentActionsService,
         FilteringService,
-        HttpClientService,
+        {
+          provide: HttpClientService,
+          useValue: httpClient
+        },
         LogsContainerService
       ],
     })

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
index 3dbd992..e6a02c0 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
@@ -29,6 +29,7 @@ import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/aud
 import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
 import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
 import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {FilteringService} from '@app/services/filtering.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
@@ -59,7 +60,8 @@ describe('ComponentActionsService', () => {
           auditLogsFields,
           serviceLogsFields,
           serviceLogsHistogramData,
-          serviceLogsTruncated
+          serviceLogsTruncated,
+          tabs
         })
       ],
       providers: [
@@ -75,6 +77,7 @@ describe('ComponentActionsService', () => {
         ServiceLogsFieldsService,
         ServiceLogsHistogramDataService,
         ServiceLogsTruncatedService,
+        TabsService,
         FilteringService,
         {
           provide: HttpClientService,

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
index 19b873c..c483cd8 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
@@ -18,16 +18,17 @@
 
 import {Injectable} from '@angular/core';
 import {AppSettingsService} from '@app/services/storage/app-settings.service';
-import {AppStateService} from '@app/services/storage/app-state.service';
+import {TabsService} from '@app/services/storage/tabs.service';
 import {CollectionModelService} from '@app/classes/models/store';
 import {FilteringService} from '@app/services/filtering.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {ServiceLog} from '@app/classes/models/service-log';
+import {getFiltersForm} from '@app/classes/filtering';
 
 @Injectable()
 export class ComponentActionsService {
 
-  constructor(private appSettings: AppSettingsService, private appState: AppStateService, private filtering: FilteringService, private logsContainer: LogsContainerService) {
+  constructor(private appSettings: AppSettingsService, private tabsStorage: TabsService, private filtering: FilteringService, private logsContainer: LogsContainerService) {
   }
 
   //TODO implement actions
@@ -39,8 +40,7 @@ export class ComponentActionsService {
   }
 
   refresh(): void {
-    // TODO implement dynamic definition of logs type
-    this.logsContainer.loadLogs('serviceLogs');
+    this.logsContainer.loadLogs();
   }
 
   openHistory() {
@@ -78,14 +78,25 @@ export class ComponentActionsService {
   }
 
   openLog(log: ServiceLog): void {
-    this.appState.setParameters({
-      isServiceLogsFileView: true,
-      activeLog: {
-        id: log.id,
-        host_name: log.host,
-        component_name: log.type
+    const tab = {
+      id: log.id,
+      type: 'serviceLogs',
+      isActive: true,
+      isCloseable: true,
+      label: `${log.host} >> ${log.type}`,
+      appState: {
+        activeLogsType: 'serviceLogs',
+        isServiceLogsFileView: true,
+        activeLog: {
+          id: log.id,
+          host_name: log.host,
+          component_name: log.type
+        },
+        activeFiltersForm: getFiltersForm('serviceLogs')
       }
-    });
+    };
+    this.tabsStorage.addInstance(tab);
+    this.logsContainer.switchTab(tab);
   }
 
   openContext(log: ServiceLog): void {

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
index f043f42..5dc38b4 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
@@ -29,6 +29,7 @@ import {AppStateService, appState} from '@app/services/storage/app-state.service
 import {ClustersService, clusters} from '@app/services/storage/clusters.service';
 import {ComponentsService, components} from '@app/services/storage/components.service';
 import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {FilteringService} from '@app/services/filtering.service';
@@ -58,7 +59,8 @@ describe('ComponentGeneratorService', () => {
           appState,
           clusters,
           components,
-          serviceLogsTruncated
+          serviceLogsTruncated,
+          tabs
         })
       ],
       providers: [
@@ -79,7 +81,8 @@ describe('ComponentGeneratorService', () => {
         AppStateService,
         ClustersService,
         ComponentsService,
-        ServiceLogsTruncatedService
+        ServiceLogsTruncatedService,
+        TabsService
       ]
     });
   });

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts
index 5d79902..2b3e326 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.spec.ts
@@ -19,6 +19,7 @@
 import {TestBed, inject} from '@angular/core/testing';
 import {StoreModule} from '@ngrx/store';
 import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
+import {AppStateService, appState} from '@app/services/storage/app-state.service';
 import {ClustersService, clusters} from '@app/services/storage/clusters.service';
 import {ComponentsService, components} from '@app/services/storage/components.service';
 import {HostsService, hosts} from '@app/services/storage/hosts.service';
@@ -43,6 +44,7 @@ describe('FilteringService', () => {
       imports: [
         StoreModule.provideStore({
           appSettings,
+          appState,
           clusters,
           components,
           hosts
@@ -51,6 +53,7 @@ describe('FilteringService', () => {
       providers: [
         FilteringService,
         AppSettingsService,
+        AppStateService,
         ClustersService,
         ComponentsService,
         HostsService,

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
index c3177cc..85dc408 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
@@ -17,7 +17,7 @@
  */
 
 import {Injectable, Input} from '@angular/core';
-import {FormControl, FormGroup} from '@angular/forms';
+import {FormGroup} from '@angular/forms';
 import {Response} from '@angular/http';
 import {Subject} from 'rxjs/Subject';
 import {Observable} from 'rxjs/Observable';
@@ -25,17 +25,22 @@ import 'rxjs/add/observable/timer';
 import 'rxjs/add/operator/takeUntil';
 import * as moment from 'moment-timezone';
 import {ListItem} from '@app/classes/list-item';
+import {FilterCondition, filters} from '@app/classes/filtering';
 import {Node} from '@app/classes/models/node';
 import {AppSettingsService} from '@app/services/storage/app-settings.service';
 import {ClustersService} from '@app/services/storage/clusters.service';
 import {ComponentsService} from '@app/services/storage/components.service';
 import {HostsService} from '@app/services/storage/hosts.service';
+import {AppStateService} from '@app/services/storage/app-state.service';
 import {HttpClientService} from '@app/services/http-client.service';
 
 @Injectable()
 export class FilteringService {
 
-  constructor(private httpClient: HttpClientService, private appSettings: AppSettingsService, private clustersStorage: ClustersService, private componentsStorage: ComponentsService, private hostsStorage: HostsService) {
+  constructor(private httpClient: HttpClientService, private appSettings: AppSettingsService, private clustersStorage: ClustersService, private componentsStorage: ComponentsService, private hostsStorage: HostsService, private appState: AppStateService) {
+    this.loadClusters();
+    this.loadComponents();
+    this.loadHosts();
     appSettings.getParameter('timeZone').subscribe(value => this.timeZone = value || this.defaultTimeZone);
     clustersStorage.getAll().subscribe((clusters: string[]): void => {
       this.filters.clusters.options = [...this.filters.clusters.options, ...clusters.map(this.getListItemFromString)];
@@ -46,6 +51,7 @@ export class FilteringService {
     hostsStorage.getAll().subscribe((hosts: Node[]): void => {
       this.filters.hosts.options = [...this.filters.hosts.options, ...hosts.map(this.getListItemFromNode)];
     });
+    appState.getParameter('activeFiltersForm').subscribe((form: FormGroup) => this.activeFiltersForm = form);
   }
 
   /**
@@ -62,7 +68,7 @@ export class FilteringService {
 
   /**
    * Get instance for dropdown list from Node object
-   * @param name {Node}
+   * @param node {Node}
    * @returns {ListItem}
    */
   private getListItemFromNode(node: Node): ListItem {
@@ -74,8 +80,6 @@ export class FilteringService {
 
   private readonly defaultTimeZone = moment.tz.guess();
 
-  private readonly paginationOptions = ['10', '25', '50', '100'];
-
   timeZone: string = this.defaultTimeZone;
 
   /**
@@ -86,326 +90,9 @@ export class FilteringService {
   @Input()
   maximumCaptureTimeLimit: number = 600000;
 
-  filters = {
-    clusters: {
-      label: 'filter.clusters',
-      options: [],
-      defaultValue: ''
-    },
-    timeRange: {
-      options: [
-        [
-          {
-            label: 'filter.timeRange.7d',
-            value: {
-              type: 'LAST',
-              unit: 'd',
-              interval: 7
-            }
-          },
-          {
-            label: 'filter.timeRange.30d',
-            value: {
-              type: 'LAST',
-              unit: 'd',
-              interval: 30
-            }
-          },
-          {
-            label: 'filter.timeRange.60d',
-            value: {
-              type: 'LAST',
-              unit: 'd',
-              interval: 60
-            }
-          },
-          {
-            label: 'filter.timeRange.90d',
-            value: {
-              type: 'LAST',
-              unit: 'd',
-              interval: 90
-            }
-          },
-          {
-            label: 'filter.timeRange.6m',
-            value: {
-              type: 'LAST',
-              unit: 'M',
-              interval: 6
-            }
-          },
-          {
-            label: 'filter.timeRange.1y',
-            value: {
-              type: 'LAST',
-              unit: 'Y',
-              interval: 1
-            }
-          },
-          {
-            label: 'filter.timeRange.2y',
-            value: {
-              type: 'LAST',
-              unit: 'Y',
-              interval: 2
-            }
-          },
-          {
-            label: 'filter.timeRange.5y',
-            value: {
-              type: 'LAST',
-              unit: 'Y',
-              interval: 5
-            }
-          }
-        ],
-        [
-          {
-            label: 'filter.timeRange.yesterday',
-            value: {
-              type: 'PAST',
-              unit: 'd'
-            }
-          },
-          // TODO implement time range calculation
-          /*
-          {
-            label: 'filter.timeRange.beforeYesterday',
-            value: {
-              type: 'PAST',
-              unit: 'd'
-            }
-          },
-          {
-            label: 'filter.timeRange.thisDayLastWeek',
-            value: {
-              type: 'PAST',
-              unit: 'd'
-            }
-          },
-          */
-          {
-            label: 'filter.timeRange.previousWeek',
-            value: {
-              type: 'PAST',
-              unit: 'w'
-            }
-          },
-          {
-            label: 'filter.timeRange.previousMonth',
-            value: {
-              type: 'PAST',
-              unit: 'M'
-            }
-          },
-          {
-            label: 'filter.timeRange.previousYear',
-            value: {
-              type: 'PAST',
-              unit: 'Y'
-            }
-          }
-        ],
-        [
-          {
-            label: 'filter.timeRange.today',
-            value: {
-              type: 'CURRENT',
-              unit: 'd'
-            }
-          },
-          {
-            label: 'filter.timeRange.thisWeek',
-            value: {
-              type: 'CURRENT',
-              unit: 'w'
-            }
-          },
-          {
-            label: 'filter.timeRange.thisMonth',
-            value: {
-              type: 'CURRENT',
-              unit: 'M'
-            }
-          },
-          {
-            label: 'filter.timeRange.thisYear',
-            value: {
-              type: 'CURRENT',
-              unit: 'Y'
-            }
-          }
-        ],
-        [
-          {
-            label: 'filter.timeRange.5min',
-            value: {
-              type: 'LAST',
-              unit: 'm',
-              interval: 5
-            }
-          },
-          {
-            label: 'filter.timeRange.15min',
-            value: {
-              type: 'LAST',
-              unit: 'm',
-              interval: 15
-            }
-          },
-          {
-            label: 'filter.timeRange.30min',
-            value: {
-              type: 'LAST',
-              unit: 'm',
-              interval: 30
-            }
-          },
-          {
-            label: 'filter.timeRange.1hr',
-            value: {
-              type: 'LAST',
-              unit: 'h',
-              interval: 1
-            }
-          },
-          {
-            label: 'filter.timeRange.3hr',
-            value: {
-              type: 'LAST',
-              unit: 'h',
-              interval: 3
-            }
-          },
-          {
-            label: 'filter.timeRange.6hr',
-            value: {
-              type: 'LAST',
-              unit: 'h',
-              interval: 6
-            }
-          },
-          {
-            label: 'filter.timeRange.12hr',
-            value: {
-              type: 'LAST',
-              unit: 'h',
-              interval: 12
-            }
-          },
-          {
-            label: 'filter.timeRange.24hr',
-            value: {
-              type: 'LAST',
-              unit: 'h',
-              interval: 24
-            }
-          },
-        ]
-      ],
-      defaultValue: {
-        type: 'LAST',
-        unit: 'h',
-        interval: 1
-      },
-      defaultLabel: 'filter.timeRange.1hr'
-    },
-    components: {
-      label: 'filter.components',
-      iconClass: 'fa fa-cubes',
-      options: [],
-      defaultValue: ''
-    },
-    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'
-        }
-      ],
-      defaultValue: ''
-    },
-    hosts: {
-      label: 'filter.hosts',
-      iconClass: 'fa fa-server',
-      options: [],
-      defaultValue: ''
-    },
-    sorting: {
-      label: 'sorting.title',
-      options: [
-        {
-          label: 'sorting.time.asc',
-          value: {
-            key: 'logtime',
-            type: 'asc'
-          }
-        },
-        {
-          label: 'sorting.time.desc',
-          value: {
-            key: 'logtime',
-            type: 'desc'
-          }
-        }
-      ],
-      defaultValue: '',
-      defaultLabel: ''
-    },
-    pageSize: {
-      label: 'pagination.title',
-      options: this.paginationOptions.map(option => {
-        return {
-          label: option,
-          value: option
-        }
-      }),
-      defaultValue: '10',
-      defaultLabel: '10'
-    },
-    page: {
-      defaultValue: 0
-    },
-    query: {}
-  };
-
-  private filtersFormItems = Object.keys(this.filters).reduce((currentObject, key) => {
-    let formControl = new FormControl(),
-      item = {
-        [key]: formControl
-      };
-    formControl.setValue(this.filters[key].defaultValue);
-    return Object.assign(currentObject, item);
-  }, {});
+  filters: {[key: string]: FilterCondition} = Object.assign({}, filters);
 
-  filtersForm = new FormGroup(this.filtersFormItems);
+  activeFiltersForm: FormGroup;
 
   queryParameterNameChange: Subject<any> = new Subject();
 
@@ -428,7 +115,7 @@ export class FilteringService {
   startCaptureTimer(): void {
     this.startCaptureTime = new Date().valueOf();
     const maxCaptureTimeInSeconds = this.maximumCaptureTimeLimit / 1000;
-    Observable.timer(0, 1000).takeUntil(this.stopTimer).subscribe(seconds => {
+    Observable.timer(0, 1000).takeUntil(this.stopTimer).subscribe((seconds: number): void => {
       this.captureSeconds = seconds;
       if (this.captureSeconds >= maxCaptureTimeInSeconds) {
         this.stopCaptureTimer();
@@ -442,7 +129,7 @@ export class FilteringService {
     this.captureSeconds = 0;
     this.stopTimer.next();
     this.setCustomTimeRange(this.startCaptureTime, this.stopCaptureTime);
-    Observable.timer(0, 1000).takeUntil(this.stopAutoRefreshCountdown).subscribe(seconds => {
+    Observable.timer(0, 1000).takeUntil(this.stopAutoRefreshCountdown).subscribe((seconds: number): void => {
       this.autoRefreshRemainingSeconds = autoRefreshIntervalSeconds - seconds;
       if (!this.autoRefreshRemainingSeconds) {
         this.stopAutoRefreshCountdown.next();
@@ -485,7 +172,7 @@ export class FilteringService {
   }
 
   setCustomTimeRange(startTime: number, endTime: number): void {
-    this.filtersForm.controls.timeRange.setValue({
+    this.activeFiltersForm.controls.timeRange.setValue({
       type: 'CUSTOM',
       start: moment(startTime),
       end: moment(endTime)

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts
index a762fef..ee0e1e7 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
@@ -29,6 +29,7 @@ import {ClustersService, clusters} from '@app/services/storage/clusters.service'
 import {ComponentsService, components} from '@app/services/storage/components.service';
 import {HostsService, hosts} from '@app/services/storage/hosts.service';
 import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
 import {HttpClientService} from '@app/services/http-client.service';
 import {FilteringService} from '@app/services/filtering.service';
 
@@ -57,7 +58,8 @@ describe('LogsContainerService', () => {
           clusters,
           components,
           hosts,
-          serviceLogsTruncated
+          serviceLogsTruncated,
+          tabs
         })
       ],
       providers: [
@@ -72,6 +74,7 @@ describe('LogsContainerService', () => {
         ComponentsService,
         HostsService,
         ServiceLogsTruncatedService,
+        TabsService,
         LogsContainerService,
         {
           provide: HttpClientService,

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
----------------------------------------------------------------------
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 0319262..e187b00 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
@@ -17,6 +17,7 @@
  */
 
 import {Injectable} from '@angular/core';
+import {Response} from '@angular/http';
 import {HttpClientService} from '@app/services/http-client.service';
 import {FilteringService} from '@app/services/filtering.service';
 import {AuditLogsService} from '@app/services/storage/audit-logs.service';
@@ -26,22 +27,28 @@ import {ServiceLogsFieldsService} from '@app/services/storage/service-logs-field
 import {ServiceLogsHistogramDataService} from '@app/services/storage/service-logs-histogram-data.service';
 import {ServiceLogsTruncatedService} from '@app/services/storage/service-logs-truncated.service';
 import {AppStateService} from '@app/services/storage/app-state.service';
+import {TabsService} from '@app/services/storage/tabs.service';
 import {ActiveServiceLogEntry} from '@app/classes/active-service-log-entry';
+import {Tab} from '@app/classes/models/tab';
+import {AuditLogField} from '@app/classes/models/audit-log-field';
+import {ServiceLogField} from '@app/classes/models/service-log-field';
+import {BarGraph} from '@app/classes/models/bar-graph';
 
 @Injectable()
 export class LogsContainerService {
 
-  constructor(private httpClient: HttpClientService, private auditLogsStorage: AuditLogsService, private auditLogsFieldsStorage: AuditLogsFieldsService, private serviceLogsStorage: ServiceLogsService, private serviceLogsFieldsStorage: ServiceLogsFieldsService, private serviceLogsHistogramStorage: ServiceLogsHistogramDataService, private serviceLogsTruncatedStorage: ServiceLogsTruncatedService, private appState: AppStateService, private filtering: FilteringService) {
+  constructor(private httpClient: HttpClientService, private auditLogsStorage: AuditLogsService, private auditLogsFieldsStorage: AuditLogsFieldsService, private serviceLogsStorage: ServiceLogsService, private serviceLogsFieldsStorage: ServiceLogsFieldsService, private serviceLogsHistogramStorage: ServiceLogsHistogramDataService, private serviceLogsTruncatedStorage: ServiceLogsTruncatedService, private appState: AppStateService, private tabsStorage: TabsService, private filtering: FilteringService) {
     appState.getParameter('activeLog').subscribe((value: ActiveServiceLogEntry | null) => this.activeLog = value);
     appState.getParameter('isServiceLogsFileView').subscribe((value: boolean): void => {
       const activeLog = this.activeLog,
-        filtersForm = this.filtering.filtersForm;
+        filtersForm = this.filtering.activeFiltersForm;
       if (value && activeLog) {
         filtersForm.controls.hosts.setValue(activeLog.host_name);
         filtersForm.controls.components.setValue(activeLog.component_name);
       }
       this.isServiceLogsFileView = value;
     });
+    appState.getParameter('activeLogsType').subscribe((value: string) => this.activeLogsType = value);
   }
 
   readonly colors = {
@@ -78,13 +85,11 @@ export class LogsContainerService {
   readonly logsTypeMap = {
     auditLogs: {
       logsModel: this.auditLogsStorage,
-      fieldsModel: this.auditLogsFieldsStorage,
-      isSetFlag: 'isAuditLogsSet'
+      fieldsModel: this.auditLogsFieldsStorage
     },
     serviceLogs: {
       logsModel: this.serviceLogsStorage,
-      fieldsModel: this.serviceLogsFieldsStorage,
-      isSetFlag: 'isServiceLogsSet'
+      fieldsModel: this.serviceLogsFieldsStorage
     }
   };
 
@@ -94,8 +99,10 @@ export class LogsContainerService {
 
   activeLog: ActiveServiceLogEntry | null = null;
 
-  loadLogs(logsType: string): void {
-    this.httpClient.get(logsType, this.getParams('listFilters')).subscribe(response => {
+  activeLogsType: string;
+
+  loadLogs = (logsType: string = this.activeLogsType): void => {
+    this.httpClient.get(logsType, this.getParams('listFilters')).subscribe((response: Response): void => {
       const jsonResponse = response.json(),
         model = this.logsTypeMap[logsType].logsModel;
       model.clear();
@@ -110,7 +117,7 @@ export class LogsContainerService {
     });
     if (logsType === 'serviceLogs') {
       // TODO rewrite to implement conditional data loading for service logs histogram or audit logs graph
-      this.httpClient.get('serviceLogsHistogram', this.getParams('histogramFilters')).subscribe(response => {
+      this.httpClient.get('serviceLogsHistogram', this.getParams('histogramFilters')).subscribe((response: Response): void => {
         const jsonResponse = response.json();
         this.serviceLogsHistogramStorage.clear();
         if (jsonResponse) {
@@ -130,7 +137,7 @@ export class LogsContainerService {
       component_name: componentName,
       scrollType: scrollType
     };
-    this.httpClient.get('serviceLogsTruncated', params).subscribe(response => {
+    this.httpClient.get('serviceLogsTruncated', params).subscribe((response: Response): void => {
       const jsonResponse = response.json();
       if (!scrollType) {
         this.serviceLogsTruncatedStorage.clear();
@@ -156,8 +163,8 @@ export class LogsContainerService {
 
   private getParams(filtersMapName: string): any {
     let params = {};
-    Object.keys(this[filtersMapName]).forEach(key => {
-      const inputValue = this.filtering.filtersForm.getRawValue()[key],
+    Object.keys(this[filtersMapName]).forEach((key: string): void => {
+      const inputValue = this.filtering.activeFiltersForm.getRawValue()[key],
         paramNames = this[filtersMapName][key];
       paramNames.forEach(paramName => {
         let value;
@@ -179,7 +186,7 @@ export class LogsContainerService {
     return params;
   }
 
-  getHistogramData(data: any[]): any {
+  getHistogramData(data: BarGraph[]): {[key: string]: number} {
     let histogramData = {};
     data.forEach(type => {
       const name = type.name;
@@ -196,4 +203,31 @@ export class LogsContainerService {
     return histogramData;
   }
 
+  loadColumnsNames(): void {
+    this.httpClient.get('serviceLogsFields').subscribe((response: Response): void => {
+      const jsonResponse = response.json();
+      if (jsonResponse) {
+        this.serviceLogsFieldsStorage.addInstances(this.getColumnsArray(jsonResponse, ServiceLogField));
+      }
+    });
+    this.httpClient.get('auditLogsFields').subscribe((response: Response): void => {
+      const jsonResponse = response.json();
+      if (jsonResponse) {
+        this.auditLogsFieldsStorage.addInstances(this.getColumnsArray(jsonResponse, AuditLogField));
+      }
+    });
+  }
+
+  private getColumnsArray(keysObject: any, fieldClass: any): any[] {
+    return Object.keys(keysObject).map((key: string): {fieldClass} => new fieldClass(key));
+  }
+
+  switchTab(activeTab: Tab): void {
+    this.appState.setParameters(activeTab.appState);
+    this.tabsStorage.mapCollection((tab: Tab): Tab => Object.assign({}, tab, {
+      isActive: tab.id === activeTab.id
+    }));
+    this.loadLogs();
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
----------------------------------------------------------------------
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 ca8a632..d700b16 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
@@ -31,6 +31,7 @@ import {serviceLogsTruncated} from '@app/services/storage/service-logs-truncated
 import {serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
 import {auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
 import {userConfigs} from '@app/services/storage/user-configs.service';
+import {tabs} from '@app/services/storage/tabs.service';
 
 export const reducers = {
   appSettings,
@@ -46,7 +47,8 @@ export const reducers = {
   clusters,
   components,
   serviceLogsFields,
-  auditLogsFields
+  auditLogsFields,
+  tabs
 };
 
 export function reducer(state: any, action: any) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/tabs.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/tabs.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/tabs.service.ts
new file mode 100644
index 0000000..93bf985
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/tabs.service.ts
@@ -0,0 +1,33 @@
+/**
+ * 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 {Store} from '@ngrx/store';
+import {initialTabs} from '@app/classes/models/tab';
+import {AppStore, CollectionModelService, getCollectionReducer} from '@app/classes/models/store';
+
+export const modelName = 'tabs';
+
+@Injectable()
+export class TabsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const tabs = getCollectionReducer(modelName, initialTabs);

http://git-wip-us.apache.org/repos/asf/ambari/blob/15cec1cb/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
----------------------------------------------------------------------
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 99ddbe5..16b4b32 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
+++ b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
@@ -2,6 +2,8 @@
   "common.title": "Log Search",
   "common.hide": "Hide",
   "common.show": "Show",
+  "common.serviceLogs": "Service Logs",
+  "common.auditLogs": "Audit Logs",
 
   "modal.submit": "OK",
   "modal.cancel": "Cancel",