ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mradhakrish...@apache.org
Subject [35/94] [abbrv] [partial] ambari git commit: AMBARI-21870. Integrate LogSearch new UI with the server and get rid of the old one (oleewere)
Date Mon, 11 Sep 2017 04:39:05 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.spec.ts
new file mode 100644
index 0000000..0d0c24c
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.spec.ts
@@ -0,0 +1,26 @@
+/**
+ * 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 {TimeZoneAbbrPipe} from './timezone-abbr.pipe';
+
+describe('TimeZoneAbbrPipe', () => {
+  it('create an instance', () => {
+    const pipe = new TimeZoneAbbrPipe();
+    expect(pipe).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.ts b/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.ts
new file mode 100644
index 0000000..f4aab0b
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/pipes/timezone-abbr.pipe.ts
@@ -0,0 +1,31 @@
+/**
+ * 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 {Pipe, PipeTransform} from '@angular/core';
+import * as moment from 'moment-timezone';
+
+@Pipe({
+  name: 'timeZoneAbbr'
+})
+export class TimeZoneAbbrPipe implements PipeTransform {
+
+  transform(value: string): string {
+    return moment.tz.zone(value).abbr(moment().valueOf());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/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
new file mode 100644
index 0000000..ff0ee37
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.spec.ts
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TestBed, inject} from '@angular/core/testing';
+import {StoreModule} from '@ngrx/store';
+import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
+
+import {ComponentActionsService} from './component-actions.service';
+
+describe('ComponentActionsService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [
+        StoreModule.provideStore({
+          appSettings
+        })
+      ],
+      providers: [
+        AppSettingsService,
+        ComponentActionsService
+      ]
+    });
+  });
+
+  it('should create service', inject([ComponentActionsService], (service: ComponentActionsService) => {
+    expect(service).toBeTruthy();
+  }));
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/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
new file mode 100644
index 0000000..a8235fa
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
@@ -0,0 +1,53 @@
+/**
+ * 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 {AppSettingsService} from '@app/services/storage/app-settings.service';
+import {CollectionModelService} from '@app/models/store.model';
+
+@Injectable()
+export class ComponentActionsService {
+
+  constructor(private appSettings: AppSettingsService) {
+  }
+
+  //TODO implement actions
+
+  undo() {
+  }
+
+  redo() {
+  }
+
+  refresh() {
+  }
+
+  openHistory() {
+  }
+
+  setTimeZone(timeZone: string): void {
+    this.appSettings.setParameter('timeZone', timeZone);
+  }
+
+  updateSelectedColumns(columnNames: string[], model: CollectionModelService): void {
+    model.mapCollection(item => Object.assign({}, item, {
+      isDisplayed: columnNames.indexOf(item.name) > -1
+    }));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/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
new file mode 100644
index 0000000..b6ec8d7
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.spec.ts
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TestBed, inject} from '@angular/core/testing';
+import {StoreModule} from '@ngrx/store';
+import {HostsService, hosts} from '@app/services/storage/hosts.service';
+import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
+import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
+import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
+import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
+import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
+import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
+import {ClustersService, clusters} from '@app/services/storage/clusters.service';
+import {ComponentsService, components} from '@app/services/storage/components.service';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {HttpClientService} from '@app/services/http-client.service';
+import {FilteringService} from '@app/services/filtering.service';
+
+import {ComponentGeneratorService} from './component-generator.service';
+
+describe('ComponentGeneratorService', () => {
+  beforeEach(() => {
+    const httpClient = {
+      get: () => {
+        return {
+          subscribe: () => {
+          }
+        }
+      }
+    };
+    TestBed.configureTestingModule({
+      imports: [
+        StoreModule.provideStore({
+          hosts,
+          auditLogs,
+          serviceLogs,
+          auditLogsFields,
+          serviceLogsFields,
+          serviceLogsHistogramData,
+          appSettings,
+          clusters,
+          components
+        })
+      ],
+      providers: [
+        ComponentGeneratorService,
+        LogsContainerService,
+        {
+          provide: HttpClientService,
+          useValue: httpClient
+        },
+        FilteringService,
+        HostsService,
+        AuditLogsService,
+        ServiceLogsService,
+        AuditLogsFieldsService,
+        ServiceLogsFieldsService,
+        ServiceLogsHistogramDataService,
+        AppSettingsService,
+        ClustersService,
+        ComponentsService
+      ]
+    });
+  });
+
+  it('should create service', inject([ComponentGeneratorService], (service: ComponentGeneratorService) => {
+    expect(service).toBeTruthy();
+  }));
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.ts
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..c49f40f
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-generator.service.ts
@@ -0,0 +1,57 @@
+/**
+ * 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, ComponentFactoryResolver, ViewContainerRef} from '@angular/core';
+import {HostsService} from '@app/services/storage/hosts.service';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {NodeBarComponent} from '@app/components/node-bar/node-bar.component';
+
+@Injectable()
+export class ComponentGeneratorService {
+
+  constructor(private resolver: ComponentFactoryResolver, private hostsStorage: HostsService, private logsContainer: LogsContainerService) {
+  }
+
+  private createComponent(type: any, container: ViewContainerRef, properties?: any): void {
+    const factory = this.resolver.resolveComponentFactory(type);
+    container.clear();
+    let component = container.createComponent(factory);
+    Object.assign(component.instance, properties);
+  }
+
+  getDataForHostsNodeBar(hostName: string, container: ViewContainerRef): void {
+    let data;
+    this.hostsStorage.getAll().subscribe(hosts => {
+      if (container && hosts && hosts.length) {
+        const selectedHost = hosts.find(host => host.name === hostName);
+        data = selectedHost.logLevelCount.map(event => {
+          return {
+            color: this.logsContainer.colors[event.name],
+            value: event.value
+          };
+        });
+        if (data.length) {
+          this.createComponent(NodeBarComponent, container, {
+            data
+          });
+        }
+      }
+    });
+  }
+
+}

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/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
new file mode 100644
index 0000000..5b9e90d
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts
@@ -0,0 +1,352 @@
+/**
+ * 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 {FormControl, FormGroup} from '@angular/forms';
+import * as moment from 'moment-timezone';
+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 {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) {
+    appSettings.getParameter('timeZone').subscribe(value => this.timeZone = value || this.defaultTimeZone);
+    clustersStorage.getAll().subscribe(clusters => {
+      this.filters.clusters.options = [...this.filters.clusters.options, ...clusters.map(this.getListItem)];
+    });
+    componentsStorage.getAll().subscribe(components => {
+      this.filters.components.options = [...this.filters.components.options, ...components.map(this.getListItem)];
+    });
+    hostsStorage.getAll().subscribe(hosts => {
+      this.filters.hosts.options = [...this.filters.hosts.options, ...hosts.map(host => {
+        return {
+          label: `${host.name} (${host.value})`,
+          value: host.name
+        };
+      })];
+    });
+  }
+
+  private getListItem(name: string): any {
+    return {
+      label: name,
+      value: name
+    };
+  }
+
+  private readonly defaultTimeZone = moment.tz.guess();
+
+  private readonly paginationOptions = ['10', '25', '50', '100'];
+
+  timeZone: string = this.defaultTimeZone;
+
+  filters = {
+    clusters: {
+      label: 'filter.clusters',
+      options: [],
+      defaultValue: ''
+    },
+    text: {
+      label: 'filter.message',
+      defaultValue: ''
+    },
+    timeRange: {
+      options: [
+        {
+          label: 'filter.timeRange.1hr',
+          value: {
+            type: 'LAST',
+            unit: 'h',
+            interval: 1
+          }
+        },
+        {
+          label: 'filter.timeRange.24hr',
+          value: {
+            type: 'LAST',
+            unit: 'h',
+            interval: 24
+          }
+        },
+        {
+          label: 'filter.timeRange.today',
+          value: {
+            type: 'CURRENT',
+            unit: 'd'
+          }
+        },
+        {
+          label: 'filter.timeRange.yesterday',
+          value: {
+            type: 'PAST',
+            unit: 'd'
+          }
+        },
+        {
+          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.thisMonth',
+          value: {
+            type: 'CURRENT',
+            unit: 'M'
+          }
+        },
+        {
+          label: 'filter.timeRange.lastMonth',
+          value: {
+            type: 'PAST',
+            unit: 'M'
+          }
+        },
+        {
+          label: 'filter.timeRange.custom',
+          value: {
+            type: 'CUSTOM'
+          }
+        }
+      ],
+      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.level.asc',
+          value: {
+            key: 'level',
+            type: 'asc'
+          }
+        },
+        {
+          label: 'sorting.level.desc',
+          value: {
+            key: 'level',
+            type: 'desc'
+          }
+        },
+        {
+          label: 'sorting.component.asc',
+          value: {
+            key: 'type',
+            type: 'asc'
+          }
+        },
+        {
+          label: 'sorting.component.desc',
+          value: {
+            key: 'type',
+            type: 'desc'
+          }
+        },
+        {
+          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
+    }
+  };
+
+  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);
+  }, {});
+
+  filtersForm = new FormGroup(this.filtersFormItems);
+
+  loadClusters(): void {
+    this.httpClient.get('clusters').subscribe(response => {
+      const clusterNames = response.json();
+      if (clusterNames) {
+        this.clustersStorage.addInstances(clusterNames);
+      }
+    });
+  }
+
+  loadComponents(): void {
+    this.httpClient.get('components').subscribe(response => {
+      const jsonResponse = response.json(),
+        components = jsonResponse && jsonResponse.groupList;
+      if (components) {
+        const componentNames = components.map(component => component.type);
+        this.componentsStorage.addInstances(componentNames);
+      }
+    });
+  }
+
+  loadHosts(): void {
+    this.httpClient.get('hosts').subscribe(response => {
+      const jsonResponse = response.json(),
+        hosts = jsonResponse && jsonResponse.vNodeList;
+      if (hosts) {
+        this.hostsStorage.addInstances(hosts);
+      }
+    });
+  }
+
+  private getStartTime(value: any, current: string): string {
+    let time;
+    if (value) {
+      const endTime = moment(moment(current).valueOf());
+      switch (value.type) {
+        case 'LAST':
+          time = endTime.subtract(value.interval, value.unit);
+          break;
+        case 'CURRENT':
+          time = moment().tz(this.timeZone).startOf(value.unit);
+          break;
+        case 'PAST':
+          time = endTime.startOf(value.unit);
+          break;
+        default:
+          break;
+      }
+    }
+    return time ? time.toISOString() : '';
+  }
+
+  private getEndTime(value: any): string {
+    let time;
+    if (value) {
+      switch (value.type) {
+        case 'LAST':
+          time = moment();
+          break;
+        case 'CURRENT':
+          time = moment().tz(this.timeZone).endOf(value.unit);
+          break;
+        case 'PAST':
+          time = moment().tz(this.timeZone).startOf(value.unit).millisecond(-1);
+          break;
+        default:
+          break;
+      }
+    }
+    return time ? time.toISOString() : '';
+  }
+
+  readonly valueGetters = {
+    end_time: this.getEndTime.bind(this),
+    start_time: this.getStartTime.bind(this),
+    to: this.getEndTime.bind(this),
+    from: this.getStartTime.bind(this),
+    sortType: value => value && value.type,
+    sortBy: value => value && value.key,
+    page: value => value == null ? value : value.toString()
+  };
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.spec.ts
new file mode 100644
index 0000000..0dfb0f3
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.spec.ts
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TestBed, inject} from '@angular/core/testing';
+import {HttpModule, Request} from '@angular/http';
+import {StoreModule} from '@ngrx/store';
+import {AppStateService, appState} from '@app/services/storage/app-state.service';
+import {HttpClientService} from './http-client.service';
+
+describe('HttpClientService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [
+        HttpModule,
+        StoreModule.provideStore({
+          appState
+        })
+      ],
+      providers: [
+        HttpClientService,
+        AppStateService
+      ]
+    });
+  });
+
+  it('should create service', inject([HttpClientService], (service: HttpClientService) => {
+    expect(service).toBeTruthy();
+  }));
+
+  describe('#generateUrlString()', () => {
+    it('should generate URL from presets', inject([HttpClientService], (service: HttpClientService) => {
+      expect(service.generateUrlString('status')).toEqual('api/v1/status');
+    }));
+
+    it('should return explicit URL', inject([HttpClientService], (service: HttpClientService) => {
+      expect(service.generateUrlString('login')).toEqual('login');
+    }));
+  });
+
+  describe('#generateUrl()', () => {
+    it('string parameter', inject([HttpClientService], (service: HttpClientService) => {
+      expect(service.generateUrl('status')).toEqual('api/v1/status');
+    }));
+
+    it('request object parameter', inject([HttpClientService], (service: HttpClientService) => {
+      let request = new Request({
+        url: 'status'
+      });
+      expect(service.generateUrl(request).url).toEqual('api/v1/status');
+    }));
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.ts
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..8fed570
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/http-client.service.ts
@@ -0,0 +1,138 @@
+/**
+ * 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 {Observable} from 'rxjs/Observable';
+import 'rxjs/add/operator/first';
+import {Http, XHRBackend, Request, RequestOptions, RequestOptionsArgs, Response, Headers, URLSearchParams} from '@angular/http';
+import {AuditLogsQueryParams} from '@app/classes/queries/audit-logs-query-params.class';
+import {ServiceLogsQueryParams} from '@app/classes/queries/service-logs-query-params.class';
+import {ServiceLogsHistogramQueryParams} from '@app/classes/queries/service-logs-histogram-query-params.class';
+import {AppStateService} from '@app/services/storage/app-state.service';
+
+@Injectable()
+export class HttpClientService extends Http {
+
+  constructor(backend: XHRBackend, defaultOptions: RequestOptions, private appState: AppStateService) {
+    super(backend, defaultOptions);
+  }
+
+  private readonly apiPrefix = 'api/v1/';
+
+  private readonly endPoints = {
+    status: {
+      url: 'status'
+    },
+    auditLogs: {
+      url: 'audit/logs',
+      params: opts => new AuditLogsQueryParams(opts)
+    },
+    auditLogsFields: {
+      url: 'audit/logs/schema/fields'
+    },
+    serviceLogs: {
+      url: 'service/logs',
+      params: opts => new ServiceLogsQueryParams(opts)
+    },
+    serviceLogsHistogram: {
+      url: 'service/logs/histogram',
+      params: opts => new ServiceLogsHistogramQueryParams(opts)
+    },
+    serviceLogsFields: {
+      url: 'service/logs/schema/fields'
+    },
+    components: {
+      url: 'service/logs/components'
+    },
+    clusters: {
+      url: 'service/logs/clusters'
+    },
+    hosts: {
+      url: 'service/logs/tree'
+    }
+  };
+
+  private readonly unauthorizedStatuses = [401, 403, 419];
+
+  private generateUrlString(url: string): string {
+    const preset = this.endPoints[url];
+    return preset ? `${this.apiPrefix}${preset.url}` : url;
+  }
+
+  private generateUrl(request: string | Request): string | Request {
+    if (typeof request === 'string') {
+      return this.generateUrlString(request);
+    }
+    if (request instanceof Request) {
+      request.url = this.generateUrlString(request.url);
+      return request;
+    }
+  }
+
+  private generateOptions(url: string, params: {[key: string]: string}): RequestOptionsArgs {
+    const preset = this.endPoints[url],
+      rawParams = preset && preset.params ? preset.params(params) : params;
+    if (rawParams) {
+      const paramsString = Object.keys(rawParams).map(key => `${key}=${rawParams[key]}`).join('&'),
+        urlParams = new URLSearchParams(paramsString, {
+          encodeKey: key => key,
+          encodeValue: value => encodeURIComponent(value)
+        });
+      return {
+        params: urlParams
+      };
+    } else {
+      return {
+        params: rawParams
+      };
+    }
+  }
+
+  private handleError(request: Observable<Response>): void {
+    request.subscribe(null, (error: any) => {
+      if (this.unauthorizedStatuses.indexOf(error.status) > -1) {
+        this.appState.setParameter('isAuthorized', false);
+      }
+    });
+  }
+
+  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
+    let req = super.request(this.generateUrl(url), options).share().first();
+    this.handleError(req);
+    return req;
+  }
+
+  get(url, params?: {[key: string]: string}): Observable<Response> {
+    return super.get(this.generateUrlString(url), this.generateOptions(url, params));
+  }
+
+  postFormData(url: string, params: {[key: string]: string}, options?: RequestOptionsArgs): Observable<Response> {
+    const encodedParams = this.generateOptions(url, params).params;
+    let body;
+    if (encodedParams && encodedParams instanceof URLSearchParams) {
+      body = encodedParams.rawParams;
+    }
+    let requestOptions = Object.assign({}, options);
+    if (!requestOptions.headers) {
+      requestOptions.headers = new Headers();
+    }
+    requestOptions.headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
+    return super.post(url, body, requestOptions);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/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
new file mode 100644
index 0000000..8ebbd72
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.spec.ts
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TestBed, inject} from '@angular/core/testing';
+import {StoreModule} from '@ngrx/store';
+import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
+import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
+import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
+import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
+import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
+import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
+import {ClustersService, clusters} from '@app/services/storage/clusters.service';
+import {ComponentsService, components} from '@app/services/storage/components.service';
+import {HostsService, hosts} from '@app/services/storage/hosts.service';
+import {HttpClientService} from '@app/services/http-client.service';
+import {FilteringService} from '@app/services/filtering.service';
+
+import {LogsContainerService} from './logs-container.service';
+
+describe('LogsContainerService', () => {
+  beforeEach(() => {
+    const httpClient = {
+      get: () => {
+        return {
+          subscribe: () => {
+          }
+        }
+      }
+    };
+    TestBed.configureTestingModule({
+      imports: [
+        StoreModule.provideStore({
+          auditLogs,
+          serviceLogs,
+          auditLogsFields,
+          serviceLogsFields,
+          serviceLogsHistogramData,
+          appSettings,
+          clusters,
+          components,
+          hosts
+        })
+      ],
+      providers: [
+        AuditLogsService,
+        ServiceLogsService,
+        AuditLogsFieldsService,
+        ServiceLogsFieldsService,
+        ServiceLogsHistogramDataService,
+        AppSettingsService,
+        ClustersService,
+        ComponentsService,
+        HostsService,
+        LogsContainerService,
+        {
+          provide: HttpClientService,
+          useValue: httpClient
+        },
+        FilteringService
+      ]
+    });
+  });
+
+  it('should create service', inject([LogsContainerService], (service: LogsContainerService) => {
+    expect(service).toBeTruthy();
+  }));
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/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
new file mode 100644
index 0000000..702deab
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
@@ -0,0 +1,148 @@
+/**
+ * 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 {HttpClientService} from '@app/services/http-client.service';
+import {FilteringService} from '@app/services/filtering.service';
+import {AuditLogsService} from '@app/services/storage/audit-logs.service';
+import {AuditLogsFieldsService} from '@app/services/storage/audit-logs-fields.service';
+import {ServiceLogsService} from '@app/services/storage/service-logs.service';
+import {ServiceLogsFieldsService} from '@app/services/storage/service-logs-fields.service';
+import {ServiceLogsHistogramDataService} from '@app/services/storage/service-logs-histogram-data.service';
+
+@Injectable()
+export class LogsContainerService {
+
+  constructor(private httpClient: HttpClientService, private auditLogsStorage: AuditLogsService, private auditLogsFieldsStorage: AuditLogsFieldsService, private serviceLogsStorage: ServiceLogsService, private serviceLogsFieldsStorage: ServiceLogsFieldsService, private serviceLogsHistogramStorage: ServiceLogsHistogramDataService, private filtering: FilteringService) {
+  }
+
+  readonly colors = {
+    WARN: '#FF8916',
+    ERROR: '#E81D1D',
+    FATAL: '#830A0A',
+    INFO: '#2577B5',
+    DEBUG: '#65E8FF',
+    TRACE: '#888',
+    UNKNOWN: '#BDBDBD'
+  };
+
+  private readonly listFilters = {
+    clusters: ['clusters'],
+    text: ['iMessage'],
+    timeRange: ['end_time', 'start_time'],
+    components: ['mustBe'],
+    levels: ['level'],
+    hosts: ['host_name'],
+    sorting: ['sortType', 'sortBy'],
+    pageSize: ['pageSize'],
+    page: ['page']
+  };
+
+  private readonly histogramFilters = {
+    clusters: ['clusters'],
+    text: ['iMessage'],
+    timeRange: ['to', 'from'],
+    components: ['mustBe'],
+    levels: ['level']
+  };
+
+  readonly logsTypeMap = {
+    auditLogs: {
+      logsModel: this.auditLogsStorage,
+      fieldsModel: this.auditLogsFieldsStorage,
+      isSetFlag: 'isAuditLogsSet'
+    },
+    serviceLogs: {
+      logsModel: this.serviceLogsStorage,
+      fieldsModel: this.serviceLogsFieldsStorage,
+      isSetFlag: 'isServiceLogsSet'
+    }
+  };
+
+  totalCount: number = 0;
+
+  loadLogs(logsType: string): void {
+    this.httpClient.get(logsType, this.getParams('listFilters')).subscribe(response => {
+      const jsonResponse = response.json();
+      this.logsTypeMap[logsType].logsModel.clear();
+      if (jsonResponse) {
+        const logs = jsonResponse.logList,
+          count = jsonResponse.totalCount || 0;
+        if (logs) {
+          this.serviceLogsStorage.addInstances(logs);
+        }
+        this.totalCount = count;
+      }
+    });
+    this.httpClient.get('serviceLogsHistogram', this.getParams('histogramFilters')).subscribe(response => {
+      const jsonResponse = response.json();
+      this.serviceLogsHistogramStorage.clear();
+      if (jsonResponse) {
+        const histogramData = jsonResponse.graphData;
+        if (histogramData) {
+          this.serviceLogsHistogramStorage.addInstances(histogramData);
+        }
+      }
+    });
+  }
+
+  private getParams(filtersMapName: string): any {
+    let params = {};
+    Object.keys(this[filtersMapName]).forEach(key => {
+      const inputValue = this.filtering.filtersForm.getRawValue()[key],
+        paramNames = this[filtersMapName][key];
+      paramNames.forEach(paramName => {
+        let value;
+        const valueGetter = this.filtering.valueGetters[paramName];
+        if (valueGetter) {
+          if (paramName === 'start_time') {
+            value = valueGetter(inputValue, params['end_time']);
+          } else if (paramName === 'from') {
+            value = valueGetter(inputValue, params['to']);
+          } else {
+            value = valueGetter(inputValue);
+          }
+        } else {
+          value = inputValue;
+        }
+        if (value != null && value !== '') {
+          params[paramName] = value;
+        }
+      });
+    }, this);
+    return params;
+  }
+
+  getHistogramData(data: any[]): any {
+    let histogramData = {};
+    data.forEach(type => {
+      const name = type.name;
+      type.dataCount.forEach(entry => {
+        const timeStamp = new Date(entry.name).valueOf();
+        if (!histogramData[timeStamp]) {
+          let initialValue = {};
+          Object.keys(this.colors).forEach(key => initialValue[key] = 0);
+          histogramData[timeStamp] = initialValue;
+        }
+        histogramData[timeStamp][name] = Number(entry.value);
+      });
+    });
+    return histogramData;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.spec.ts
new file mode 100644
index 0000000..410f70d
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.spec.ts
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TestBed, inject} from '@angular/core/testing';
+import {mockApiDataService} from './mock-api-data.service';
+
+describe('mockApiDataService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [mockApiDataService]
+    });
+  });
+
+  it('should create service', inject([mockApiDataService], (service: mockApiDataService) => {
+    expect(service).toBeTruthy();
+  }));
+
+  describe('#parseUrl()', () => {
+    const cases = [
+      {
+        url: 'root',
+        base: '/',
+        collectionName: 'root',
+        query: '',
+        title: 'one-level depth url, no query params'
+      },
+      {
+        url: 'root?param0=1&param1=2',
+        base: '/',
+        collectionName: 'root',
+        query: 'param0=1&param1=2',
+        title: 'one-level depth url with query params'
+      },
+      {
+        url: 'root/resources/collection',
+        base: 'root/resources/',
+        collectionName: 'collection',
+        query: '',
+        title: 'more than one-level depth url, no query params'
+      },
+      {
+        url: 'root/resources/collection?param0=1&param1=2',
+        base: 'root/resources/',
+        collectionName: 'collection',
+        query: 'param0=1&param1=2',
+        title: 'more than one-level depth url with query params'
+      }
+    ];
+
+    cases.forEach(test => {
+      describe(test.title, () => {
+        it('base', inject([mockApiDataService], (service: mockApiDataService) => {
+          expect(service.parseUrl(test.url).base).toEqual(test.base);
+        }));
+
+        it('collectionName', inject([mockApiDataService], (service: mockApiDataService) => {
+          expect(service.parseUrl(test.url).collectionName).toEqual(test.collectionName);
+        }));
+
+        it('query', inject([mockApiDataService], (service: mockApiDataService) => {
+          expect(service.parseUrl(test.url).query.toString()).toEqual(test.query);
+        }));
+      });
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
new file mode 100644
index 0000000..ec89d9f
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
@@ -0,0 +1,178 @@
+/**
+ * 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 {URLSearchParams, Response, ResponseOptions} from '@angular/http';
+import {InMemoryDbService, InMemoryBackendService, createErrorResponse} from 'angular-in-memory-web-api';
+import {Observable} from 'rxjs/Observable';
+import {Subscriber} from 'rxjs/Subscriber';
+import * as moment from 'moment';
+import {mockData} from '@app/mock-data';
+
+export class mockBackendService extends InMemoryBackendService {
+  getLocation(url: string): any {
+    return super.getLocation(url);
+  }
+}
+
+export class mockApiDataService implements InMemoryDbService {
+
+  private readonly filterMap = {
+    'api/v1/service/logs': {
+      pathToCollection: 'logList',
+      totalCountKey: 'totalCount',
+      filters: {
+        clusters: {
+          key: 'cluster',
+          isValuesList: true
+        },
+        mustBe: {
+          key: 'type',
+          isValuesList: true
+        },
+        level: {
+          key: 'level',
+          isValuesList: true
+        },
+        iMessage: {
+          key: 'log_message',
+          filterFunction: (value, filterValue) => value.toLowerCase().indexOf(filterValue.toLowerCase()) > -1
+        },
+        start_time: {
+          key: 'logtime',
+          filterFunction: (value, filterValue) => value >= moment(filterValue).valueOf()
+        },
+        end_time: {
+          key: 'logtime',
+          filterFunction: (value, filterValue) => value < moment(filterValue).valueOf()
+        },
+        host_name: {
+          key: 'host',
+          isValuesList: true
+        }
+      }
+    }
+  };
+
+  parseUrl(url: string): any {
+    const urlLocation = mockBackendService.prototype.getLocation(url),
+      query = urlLocation.search && new URLSearchParams(urlLocation.search.substr(1), {
+          encodeKey: key => key,
+          encodeValue: value => value
+        }),
+      splitUrl = urlLocation.pathname.substr(1).split('/'),
+      urlPartsCount = splitUrl.length,
+      collectionName = splitUrl[urlPartsCount - 1],
+      base = splitUrl.slice(0, urlPartsCount - 1).join('/') + '/';
+    return {
+      base: base,
+      collectionName: collectionName,
+      query: query
+    };
+  }
+
+  get(interceptorArgs: any): Observable<Response> {
+    const query = interceptorArgs.requestInfo.query,
+      path = interceptorArgs.requestInfo.base + interceptorArgs.requestInfo.collectionName,
+      pathArray = path.split('/').filter(part => part !== '');
+    if (query && query.paramsMap.has('static') && interceptorArgs.passThruBackend) {
+      return interceptorArgs.passThruBackend.createConnection(interceptorArgs.requestInfo.req).response;
+    } else {
+      let is404 = false;
+      const allData = pathArray.reduce((currentObject, currentKey, index, array) => {
+        if (!currentObject && index < array.length - 1) {
+          return {};
+        } else if (currentObject.hasOwnProperty(currentKey)) {
+          return currentObject[currentKey];
+        } else {
+          is404 = true;
+          return {};
+        }
+      }, interceptorArgs.db);
+      if (is404) {
+        return new Observable<Response>((subscriber: Subscriber<Response>) => subscriber.error(new Response(createErrorResponse(
+          interceptorArgs.requestInfo.req, 404, 'Not found'
+        ))));
+      } else {
+        let filteredData;
+        const filterMapItem = this.filterMap[path];
+        if (query && filterMapItem) {
+          filteredData = {};
+          const pathToCollection = filterMapItem.pathToCollection,
+            collection = allData[pathToCollection];
+          let filteredCollection = collection.filter(item => {
+            let result = true;
+              query.paramsMap.forEach((value, key) => {
+              const paramValue = decodeURIComponent(value[0]),
+                paramFilter = filterMapItem.filters[key],
+                paramValuesList = paramFilter && paramFilter.isValuesList && paramValue ? paramValue.split(',') : [],
+                currentValue = paramFilter && item[paramFilter.key];
+              if (paramFilter &&
+                ((paramFilter.filterFunction && !paramFilter.filterFunction(currentValue, paramValue)) ||
+                (!paramFilter.filterFunction && !paramFilter.isValuesList && currentValue !== paramValue) ||
+                (!paramFilter.filterFunction && paramFilter.isValuesList && paramValuesList.indexOf(currentValue) === -1))) {
+                result = false;
+              }
+            });
+            return result;
+          });
+          if (query.paramsMap.has('sortBy') && query.paramsMap.has('sortType')) {
+            const sortKey = query.paramsMap.get('sortBy')[0],
+              sortType = query.paramsMap.get('sortType')[0];
+            filteredCollection.sort((a, b) => {
+              const itemA = a[sortKey],
+                itemB = b[sortKey];
+              let ascResult;
+              if (itemA > itemB) {
+                ascResult = 1;
+              } else if (itemA < itemB) {
+                ascResult = -1;
+              } else {
+                ascResult = 0;
+              }
+              return ascResult * Math.pow(-1, Number(sortType === 'desc'));
+            });
+          }
+          if (filterMapItem.totalCountKey) {
+            filteredData[filterMapItem.totalCountKey] = filteredCollection.length;
+          }
+          if (query && query.paramsMap.has('page') && query.paramsMap.has('pageSize')) {
+            const page = parseInt(query.paramsMap.get('page')[0]),
+              pageSize = parseInt(query.paramsMap.get('pageSize')[0]);
+            filteredCollection = filteredCollection.slice(page * pageSize, (page + 1) * pageSize);
+          }
+          filteredData[pathToCollection] = filteredCollection;
+        } else {
+          filteredData = allData;
+        }
+        return new Observable<Response>((subscriber: Subscriber<Response>) => subscriber.next(new Response(new ResponseOptions({
+          status: 200,
+          body: filteredData
+        }))));
+      }
+    }
+  }
+
+  post(interceptorArgs: any) {
+    // TODO implement posting data to mock object except login call
+    return this.get(interceptorArgs);
+  }
+
+  createDb() {
+    return mockData;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-settings.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-settings.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-settings.service.ts
new file mode 100644
index 0000000..6de9988
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-settings.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 {defaultSettings} from '@app/models/app-settings.model';
+import {AppStore, ObjectModelService, getObjectReducer} from '@app/models/store.model';
+
+export const modelName = 'appSettings';
+
+@Injectable()
+export class AppSettingsService extends ObjectModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const appSettings = getObjectReducer(modelName, defaultSettings);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-state.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-state.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-state.service.ts
new file mode 100644
index 0000000..d77d80f
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/app-state.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 {initialState} from '@app/models/app-state.model';
+import {AppStore, ObjectModelService, getObjectReducer} from '@app/models/store.model';
+
+export const modelName = 'appState';
+
+@Injectable()
+export class AppStateService extends ObjectModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const appState = getObjectReducer(modelName, initialState);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs-fields.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs-fields.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs-fields.service.ts
new file mode 100644
index 0000000..bb8c661
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs-fields.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'auditLogsFields';
+
+@Injectable()
+export class AuditLogsFieldsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const auditLogsFields = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs.service.ts
new file mode 100644
index 0000000..bc33bd9
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/audit-logs.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'auditLogs';
+
+@Injectable()
+export class AuditLogsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const auditLogs = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/clusters.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/clusters.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/clusters.service.ts
new file mode 100644
index 0000000..f21a8f9
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/clusters.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'clusters';
+
+@Injectable()
+export class ClustersService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const clusters = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/components.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/components.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/components.service.ts
new file mode 100644
index 0000000..6b2a0ba
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/components.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'components';
+
+@Injectable()
+export class ComponentsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const components = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/filters.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/filters.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/filters.service.ts
new file mode 100644
index 0000000..b850006
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/filters.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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'filters';
+
+@Injectable()
+export class FiltersService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const filters = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/graphs.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/graphs.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/graphs.service.ts
new file mode 100644
index 0000000..e541444
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/graphs.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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'graphs';
+
+@Injectable()
+export class GraphsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const graphs = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/hosts.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/hosts.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/hosts.service.ts
new file mode 100644
index 0000000..0cb0a74
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/hosts.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'hosts';
+
+@Injectable()
+export class HostsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const hosts = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/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
new file mode 100644
index 0000000..08f237d
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
@@ -0,0 +1,52 @@
+/**
+ * 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 {combineReducers} from '@ngrx/store';
+import {appSettings} from '@app/services/storage/app-settings.service';
+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';
+import {serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
+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';
+
+export const reducers = {
+  appSettings,
+  appState,
+  auditLogs,
+  serviceLogs,
+  serviceLogsHistogramData,
+  graphs,
+  hosts,
+  userConfigs,
+  filters,
+  clusters,
+  components,
+  serviceLogsFields,
+  auditLogsFields
+};
+
+export function reducer(state: any, action: any) {
+  return (combineReducers(reducers))(state, action);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-fields.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-fields.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-fields.service.ts
new file mode 100644
index 0000000..0082cd6
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-fields.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'serviceLogsFields';
+
+@Injectable()
+export class ServiceLogsFieldsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const serviceLogsFields = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-histogram-data.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-histogram-data.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-histogram-data.service.ts
new file mode 100644
index 0000000..e680777
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs-histogram-data.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'serviceLogsHistogramData';
+
+@Injectable()
+export class ServiceLogsHistogramDataService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const serviceLogsHistogramData = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs.service.ts
new file mode 100644
index 0000000..f0ff0d7
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/service-logs.service.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'serviceLogs';
+
+@Injectable()
+export class ServiceLogsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const serviceLogs = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/user-configs.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/user-configs.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/user-configs.service.ts
new file mode 100644
index 0000000..1596e78
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/user-configs.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 {AppStore, CollectionModelService, getCollectionReducer} from '@app/models/store.model';
+
+export const modelName = 'userConfigs';
+
+@Injectable()
+export class UserConfigsService extends CollectionModelService {
+  constructor(store: Store<AppStore>) {
+    super(modelName, store);
+  }
+}
+
+export const userConfigs = getCollectionReducer(modelName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..a4a0cf8
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
@@ -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.
+ */
+
+import {TestBed, inject} from '@angular/core/testing';
+
+import {UtilsService} from './utils.service';
+
+describe('UtilsService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [UtilsService]
+    });
+  });
+
+  it('should create service', inject([UtilsService], (service: UtilsService) => {
+    expect(service).toBeTruthy();
+  }));
+
+  describe('#updateMultiSelectValue()', () => {
+    const cases = [
+      {
+        currentValue: '',
+        value: 'v0',
+        isChecked: true,
+        result: 'v0',
+        title: 'check; no checked items before'
+      },
+      {
+        currentValue: 'v1,v2',
+        value: 'v3',
+        isChecked: true,
+        result: 'v1,v2,v3',
+        title: 'check'
+      },
+      {
+        currentValue: 'v4,v5',
+        value: 'v4',
+        isChecked: false,
+        result: 'v5',
+        title: 'uncheck'
+      },
+      {
+        currentValue: 'v6,v7',
+        value: 'v6',
+        isChecked: true,
+        result: 'v6,v7',
+        title: 'avoid repeating check action'
+      },
+      {
+        currentValue: 'v8,v9',
+        value: 'v10',
+        isChecked: false,
+        result: 'v8,v9',
+        title: 'avoid repeating uncheck action'
+      },
+      {
+        currentValue: 'v11',
+        value: 'v11',
+        isChecked: false,
+        result: '',
+        title: 'uncheck last item'
+      }
+    ];
+
+    cases.forEach(test => {
+      it(test.title, inject([UtilsService], (service: UtilsService) => {
+        expect(service.updateMultiSelectValue(test.currentValue, test.value, test.isChecked)).toEqual(test.result);
+      }));
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/02360dd5/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..9f6cacd
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
@@ -0,0 +1,46 @@
+/**
+ * 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';
+
+@Injectable()
+export class UtilsService {
+
+  valueHasChanged(currentValue: any, newValue: any): boolean {
+    if (newValue == null) {
+      return false;
+    }
+    if (typeof newValue === 'object') {
+      return JSON.stringify(currentValue) !== JSON.stringify(newValue);
+    } else {
+      return currentValue !== newValue;
+    }
+  }
+
+  updateMultiSelectValue(currentValue: string, value: string, isChecked: boolean): string {
+    let valuesArray = currentValue ? currentValue.split(',') : [],
+      valuePosition = valuesArray.indexOf(value);
+    if (isChecked && valuePosition === -1) {
+      valuesArray.push(value);
+    } else if (!isChecked && valuePosition > -1) {
+      valuesArray.splice(valuePosition, 1);
+    }
+    return valuesArray.join(',');
+  }
+
+}


Mime
View raw message