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¶m1=2', + base: '/', + collectionName: 'root', + query: 'param0=1¶m1=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¶m1=2', + base: 'root/resources/', + collectionName: 'collection', + query: 'param0=1¶m1=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(','); + } + +}