Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 4B3E0200D22 for ; Mon, 11 Sep 2017 06:38:49 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 49D301609C0; Mon, 11 Sep 2017 04:38:49 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 425B31609C4 for ; Mon, 11 Sep 2017 06:38:47 +0200 (CEST) Received: (qmail 16292 invoked by uid 500); 11 Sep 2017 04:38:46 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 9377 invoked by uid 99); 11 Sep 2017 04:38:34 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 11 Sep 2017 04:38:33 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 525A8F574D; Mon, 11 Sep 2017 04:38:33 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mradhakrishnan@apache.org To: commits@ambari.apache.org Date: Mon, 11 Sep 2017 04:39:43 -0000 Message-Id: <447c3c1d037d4a4c84100241624ca34c@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [73/94] [abbrv] ambari git commit: AMBARI-21905 Log Search UI: implement combo search filter. (ababiichuk) archived-at: Mon, 11 Sep 2017 04:38:49 -0000 AMBARI-21905 Log Search UI: implement combo search filter. (ababiichuk) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/a10e3887 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a10e3887 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a10e3887 Branch: refs/heads/branch-feature-AMBARI-14714 Commit: a10e3887c714e6bdeb83c21b2d8ecfbba438639e Parents: ab06654 Author: ababiichuk Authored: Thu Sep 7 18:13:39 2017 +0300 Committer: ababiichuk Committed: Thu Sep 7 18:13:39 2017 +0300 ---------------------------------------------------------------------- .../ambari-logsearch-web/package.json | 1 + .../ambari-logsearch-web/src/app/app.module.ts | 10 +- ...service-logs-histogram-query-params.class.ts | 2 + .../dropdown-list/dropdown-list.component.less | 2 +- .../filter-text-field.component.html | 21 --- .../filter-text-field.component.less | 33 ---- .../filter-text-field.component.spec.ts | 82 --------- .../filter-text-field.component.ts | 87 --------- .../filters-panel/filters-panel.component.html | 10 +- .../filters-panel/filters-panel.component.less | 16 +- .../filters-panel.component.spec.ts | 22 ++- .../filters-panel/filters-panel.component.ts | 37 +++- .../search-box/search-box.component.html | 31 ++++ .../search-box/search-box.component.less | 118 +++++++++++++ .../search-box/search-box.component.spec.ts | 63 +++++++ .../search-box/search-box.component.ts | 176 +++++++++++++++++++ .../src/app/components/variables.less | 24 ++- .../src/app/models/app-state.model.ts | 4 +- .../src/app/services/filtering.service.ts | 35 +++- .../src/app/services/logs-container.service.ts | 6 +- .../src/app/services/utils.service.ts | 4 + ambari-logsearch/ambari-logsearch-web/yarn.lock | 4 + 22 files changed, 533 insertions(+), 255 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/package.json ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/package.json b/ambari-logsearch/ambari-logsearch-web/package.json index 96733eb..92c5043 100644 --- a/ambari-logsearch/ambari-logsearch-web/package.json +++ b/ambari-logsearch/ambari-logsearch-web/package.json @@ -33,6 +33,7 @@ "jquery": "^1.12.4", "moment": "^2.18.1", "moment-timezone": "^0.5.13", + "ng2-auto-complete": "^0.12.0", "ngx-bootstrap": "^1.6.6", "rxjs": "^5.1.0", "zone.js": "^0.8.4" http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts index c08cb3a..c15ecbc 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts @@ -27,7 +27,10 @@ import {TranslateHttpLoader} from '@ngx-translate/http-loader'; import {StoreModule} from '@ngrx/store'; import {MomentModule} from 'angular2-moment'; import {MomentTimezoneModule} from 'angular-moment-timezone'; +import {Ng2AutoCompleteModule} from 'ng2-auto-complete'; + import {environment} from '@envs/environment'; + import {mockApiDataService} from '@app/services/mock-api-data.service' import {HttpClientService} from '@app/services/http-client.service'; import {ComponentActionsService} from '@app/services/component-actions.service'; @@ -59,7 +62,6 @@ import {MainContainerComponent} from '@app/components/main-container/main-contai import {FiltersPanelComponent} from '@app/components/filters-panel/filters-panel.component'; import {FilterDropdownComponent} from '@app/components/filter-dropdown/filter-dropdown.component'; import {DropdownListComponent} from '@app/components/dropdown-list/dropdown-list.component'; -import {FilterTextFieldComponent} from '@app/components/filter-text-field/filter-text-field.component'; import {FilterButtonComponent} from '@app/components/filter-button/filter-button.component'; import {AccordionPanelComponent} from '@app/components/accordion-panel/accordion-panel.component'; import {LogsListComponent} from '@app/components/logs-list/logs-list.component'; @@ -71,6 +73,7 @@ import {LogsContainerComponent} from '@app/components/logs-container/logs-contai import {ModalComponent} from '@app/components/modal/modal.component'; import {TimeZonePickerComponent} from '@app/components/timezone-picker/timezone-picker.component'; import {NodeBarComponent} from '@app/components/node-bar/node-bar.component'; +import {SearchBoxComponent} from '@app/components/search-box/search-box.component'; import {TimeZoneAbbrPipe} from '@app/pipes/timezone-abbr.pipe'; @@ -104,7 +107,6 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR FiltersPanelComponent, DropdownListComponent, FilterDropdownComponent, - FilterTextFieldComponent, FilterButtonComponent, AccordionPanelComponent, LogsListComponent, @@ -116,6 +118,7 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR ModalComponent, TimeZonePickerComponent, NodeBarComponent, + SearchBoxComponent, TimeZoneAbbrPipe ], imports: [ @@ -133,7 +136,8 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR }), StoreModule.provideStore(reducer), MomentModule, - MomentTimezoneModule + MomentTimezoneModule, + Ng2AutoCompleteModule ], providers: [ HttpClientService, http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/classes/queries/service-logs-histogram-query-params.class.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/queries/service-logs-histogram-query-params.class.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/queries/service-logs-histogram-query-params.class.ts index 87e82f6..572af03 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/queries/service-logs-histogram-query-params.class.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/queries/service-logs-histogram-query-params.class.ts @@ -66,4 +66,6 @@ export class ServiceLogsHistogramQueryParams extends QueryParams { clusters?: string; iMessage?: string; level?: string; + includeQuery?: string; + excludeQuery?: string; } http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.less index d47160f..6faa192 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.less +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.less @@ -19,7 +19,7 @@ @import '../variables'; :host { - max-height: 500px; // TODO get rid of magic number, base on actual design + max-height: @dropdown-max-height; overflow-y: auto; .list-item-label { http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.html deleted file mode 100644 index 3f00e8b..0000000 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.html +++ /dev/null @@ -1,21 +0,0 @@ - - -
- {{label | translate}} - -
http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.less deleted file mode 100644 index 1395959..0000000 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.less +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@import '../variables'; - -.input-group { - border: @input-border; - border-right-width: 0; -} - -.input-group-addon { - border: none; - background-color: transparent; - text-transform: uppercase; - - & + input { - border: none; - } -} http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.spec.ts deleted file mode 100644 index 71039ed..0000000 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import {Http} from '@angular/http'; -import {FormsModule} from '@angular/forms'; -import {TranslateModule, TranslateLoader} from '@ngx-translate/core'; -import {TranslateHttpLoader} from '@ngx-translate/http-loader'; -import {StoreModule} from '@ngrx/store'; -import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service'; -import {FilteringService} from '@app/services/filtering.service'; -import {UtilsService} from '@app/services/utils.service'; -import {ComponentActionsService} from '@app/services/component-actions.service'; - -import {FilterTextFieldComponent} from './filter-text-field.component'; - -export function HttpLoaderFactory(http: Http) { - return new TranslateHttpLoader(http, 'assets/i18n/', '.json'); -} - -describe('FilterTextFieldComponent', () => { - let component: FilterTextFieldComponent; - let fixture: ComponentFixture; - const filtering = { - filters: { - f: {} - } - }; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [FilterTextFieldComponent], - imports: [ - FormsModule, - TranslateModule.forRoot({ - provide: TranslateLoader, - useFactory: HttpLoaderFactory, - deps: [Http] - }), - StoreModule.provideStore({ - appSettings - }) - ], - providers: [ - AppSettingsService, - { - provide: FilteringService, - useValue: filtering - }, - UtilsService, - ComponentActionsService - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(FilterTextFieldComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create component', () => { - expect(component).toBeTruthy(); - }); -}); http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.ts deleted file mode 100644 index 2b6bfea..0000000 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-text-field/filter-text-field.component.ts +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import {Component, Input, forwardRef} from '@angular/core'; -import {ControlValueAccessor, NG_VALUE_ACCESSOR, FormGroup} from '@angular/forms'; -import {Subject} from 'rxjs/Subject'; -import 'rxjs/add/operator/debounceTime'; -import {UtilsService} from '@app/services/utils.service'; - -@Component({ - selector: 'filter-text-field', - templateUrl: './filter-text-field.component.html', - styleUrls: ['./filter-text-field.component.less'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => FilterTextFieldComponent), - multi: true - } - ] -}) -export class FilterTextFieldComponent implements ControlValueAccessor { - - constructor(private utils: UtilsService) { - this.valueSubject.debounceTime(this.debounceInterval).subscribe(value => this.updateValue({ - value - })); - } - - @Input() - label: string; - - private selectedValue: string; - - private onChange: (fn: any) => void; - - private readonly debounceInterval = 1500; - - instantValue: string; - - private valueSubject = new Subject(); - - get value(): any { - return this.selectedValue; - } - - set value(newValue: any) { - this.selectedValue = newValue; - this.onChange(newValue); - } - - updateValue(options: any) { - const value = options && options.value; - if (this.utils.valueHasChanged(this.selectedValue, value)) { - this.value = value; - } - } - - writeValue() { - } - - registerOnChange(callback: any): void { - this.onChange = callback; - } - - registerOnTouched() { - } - - updateInstantValue(value: string): void { - this.valueSubject.next(value); - } - -} http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html index 6df6988..5820b82 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html @@ -18,12 +18,12 @@
- + [defaultLabel]="filters.clusters.defaultLabel" [isMultipleChoice]="true" + class="filter-input"> + - + [defaultLabel]="filters.timeRange.defaultLabel" class="filter-input"> + http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.less index 9ab09ef..6b2408d 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.less +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.less @@ -24,7 +24,8 @@ background-color: @filters-panel-background-color; .filter-input-container { - .flex-vertical-align; + display: flex; + align-items: flex-start; justify-content: flex-start; .btn-success { @@ -32,7 +33,7 @@ border-bottom-left-radius: 0; } - filter-dropdown, dropdown-button, timezone-picker { + .filter-input { border: @input-border; &:not(:last-child) { @@ -40,12 +41,19 @@ } &:first-child { - border-radius: @button-border-radius 0 0 @button-border-radius; + border-top-left-radius: @button-border-radius; + border-bottom-left-radius: @button-border-radius; } &:last-child { - border-radius: 0 @button-border-radius @button-border-radius 0; + border-top-right-radius: @button-border-radius; + border-bottom-right-radius: @button-border-radius; } } + + search-box.filter-input:not(:last-child) { + border-right-width: @input-border-width; + margin-right: -1 * (@input-border-width); + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.spec.ts index b1cf990..2ced41e 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.spec.ts @@ -26,9 +26,16 @@ import {AppSettingsService, appSettings} from '@app/services/storage/app-setting import {ClustersService, clusters} from '@app/services/storage/clusters.service'; import {ComponentsService, components} from '@app/services/storage/components.service'; import {HostsService, hosts} from '@app/services/storage/hosts.service'; +import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service'; +import {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 {AppStateService, appState} from '@app/services/storage/app-state.service'; import {FilteringService} from '@app/services/filtering.service'; import {HttpClientService} from '@app/services/http-client.service'; import {UtilsService} from '@app/services/utils.service'; +import {LogsContainerService} from '@app/services/logs-container.service'; import {FiltersPanelComponent} from './filters-panel.component'; @@ -56,7 +63,13 @@ describe('FiltersPanelComponent', () => { appSettings, clusters, components, - hosts + hosts, + auditLogs, + serviceLogs, + auditLogsFields, + serviceLogsFields, + serviceLogsHistogramData, + appState }), TranslateModule.forRoot({ provide: TranslateLoader, @@ -69,7 +82,14 @@ describe('FiltersPanelComponent', () => { ClustersService, ComponentsService, HostsService, + AuditLogsService, + ServiceLogsService, + AuditLogsFieldsService, + ServiceLogsFieldsService, + ServiceLogsHistogramDataService, + AppStateService, FilteringService, + LogsContainerService, { provide: HttpClientService, useValue: httpClient http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts index e407021..644048f 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts @@ -18,7 +18,10 @@ import {Component} from '@angular/core'; import {FormGroup} from '@angular/forms'; +import {TranslateService} from '@ngx-translate/core'; import {FilteringService} from '@app/services/filtering.service'; +import {LogsContainerService} from '@app/services/logs-container.service'; +import {AppStateService} from '@app/services/storage/app-state.service'; @Component({ selector: 'filters-panel', @@ -27,12 +30,38 @@ import {FilteringService} from '@app/services/filtering.service'; }) export class FiltersPanelComponent { - constructor(private filtering: FilteringService) { - this.filtering.loadClusters(); - this.filtering.loadComponents(); - this.filtering.loadHosts(); + constructor(private translate: TranslateService, private filtering: FilteringService, private logsContainer: LogsContainerService, private appState: AppStateService) { + appState.getParameter('activeLogsType').subscribe(value => { + this.logsType = value; + logsContainer.logsTypeMap[value].fieldsModel.getAll().subscribe(fields => { + if (fields.length) { + const items = fields.filter(field => this.excludedParameters.indexOf(field.name) === -1).map(field => { + return { + name: field.displayName || field.name, + value: field.name + }; + }), + labelKeys = items.map(item => item.name); + translate.get(labelKeys).first().subscribe(translation => this.searchBoxItems = items.map(item => { + return { + name: translation[item.name], + value: item.value + }; + })); + } + }) + }); + filtering.loadClusters(); + filtering.loadComponents(); + filtering.loadHosts(); } + private readonly excludedParameters = ['cluster', 'host', 'level', 'type', 'logtime']; + + private logsType: string; // TODO implement setting the parameter depending on user's navigation + + searchBoxItems: any[] = []; + get filters(): any { return this.filtering.filters; } http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.html new file mode 100644 index 0000000..64e15dc --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.html @@ -0,0 +1,31 @@ + + + +{{activeItem.name | translate}}: +
+ + +
+
\ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.less new file mode 100644 index 0000000..cccf5d5 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.less @@ -0,0 +1,118 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import '../variables'; + +@inactive-input-width: 1px; +@label-margin: 2px; +.collapsed-form-control { + width: 0; + padding: 0; +} + +:host { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + width: 100%; + border: @input-border; + cursor: text; + + .parameter-label { + // TODO implement actual styles + margin: @label-margin; + padding: @label-margin; + background-color: @main-background-color; + font-size: 0.8em; + + .parameter-value { + font-weight: normal; + } + + .remove-parameter { + cursor: pointer; + } + } + + .active-parameter-label { + font-weight: bold; + margin: 0 @label-margin; + } + + .search-item-container { + position: relative; + min-width: @inactive-input-width; + height: @input-height; + + .search-item-input { + border: none; + box-shadow: none; + } + + .parameter-input { + width: @inactive-input-width; + } + + .value-input { + .collapsed-form-control; + } + + .search-item-text { + visibility: hidden; + padding: 0 @input-padding; + } + + &.active { + min-width: @dropdown-min-width; + + .parameter-input { + width: 100%; + } + + .value-input { + .collapsed-form-control; + } + + &.value { + /deep/ .ng2-auto-complete-wrapper, .parameter-input { + display: none; + } + + .value-input { + width: 100%; + } + } + } + + /deep/ .ng2-auto-complete { + cursor: pointer; + .dropdown-list-default; + + > ul { + border: none; + + li { + border: none; + background-color: initial; + .dropdown-item-default; + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.spec.ts new file mode 100644 index 0000000..2b3a957 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.spec.ts @@ -0,0 +1,63 @@ +/** + * 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 {NO_ERRORS_SCHEMA} from '@angular/core'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {Http} from '@angular/http'; +import {TranslateModule, TranslateLoader} from '@ngx-translate/core'; +import {TranslateHttpLoader} from '@ngx-translate/http-loader'; +import {UtilsService} from '@app/services/utils.service'; + +import {SearchBoxComponent} from './search-box.component'; + +export function HttpLoaderFactory(http: Http) { + return new TranslateHttpLoader(http, 'assets/i18n/', '.json'); +} + +describe('SearchBoxComponent', () => { + let component: SearchBoxComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [SearchBoxComponent], + imports: [ + TranslateModule.forRoot({ + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [Http] + }) + ], + providers: [ + UtilsService + ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SearchBoxComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create component', () => { + expect(component).toBeTruthy(); + }); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts new file mode 100644 index 0000000..82c455e --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts @@ -0,0 +1,176 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Component, OnInit, OnDestroy, Input, ViewChild, ElementRef, forwardRef} from '@angular/core'; +import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; +import {UtilsService} from '@app/services/utils.service'; + +@Component({ + selector: 'search-box', + templateUrl: './search-box.component.html', + styleUrls: ['./search-box.component.less'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SearchBoxComponent), + multi: true + } + ] +}) +export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccessor { + + constructor(private element: ElementRef, private utils: UtilsService) { + this.rootElement = element.nativeElement; + this.rootElement.addEventListener('click', this.onRootClick); + this.rootElement.addEventListener('keydown', this.onRootKeyDown); + } + + ngOnInit() { + this.parameterInput = this.parameterInputRef.nativeElement; + this.valueInput = this.valueInputRef.nativeElement; + this.parameterInput.addEventListener('focus', this.onParameterInputFocus); + this.parameterInput.addEventListener('blur', this.onParameterInputBlur); + this.valueInput.addEventListener('blur', this.onValueInputBlur); + } + + ngOnDestroy() { + this.rootElement.removeEventListener('click', this.onRootClick); + this.rootElement.removeEventListener('keydown', this.onRootKeyDown); + this.parameterInput.removeEventListener('focus', this.onParameterInputFocus); + this.parameterInput.removeEventListener('blur', this.onParameterInputBlur); + this.valueInput.removeEventListener('blur', this.onValueInputBlur); + } + + private currentId: number = 0; + + isActive: boolean = false; + + isParameterInput: boolean = false; + + isValueInput: boolean = false; + + currentValue: string; + + @Input() + items: any[] = []; + + @ViewChild('parameterInput') + parameterInputRef: ElementRef; + + @ViewChild('valueInput') + valueInputRef: ElementRef; + + rootElement: HTMLElement; + + parameterInput: HTMLElement; + + valueInput: HTMLElement; + + activeItem?: any; + + parameters: any[] = []; + + private onChange: (fn: any) => void; + + private onRootClick = (): void => { + if (!this.isActive) { + this.parameterInput.focus(); + } + }; + + private onRootKeyDown = (event: KeyboardEvent): void => { + if (this.utils.isEnterPressed(event)) { + event.preventDefault(); + } + }; + + private onParameterInputFocus = (): void => { + this.isActive = true; + this.isValueInput = false; + this.isParameterInput = true; + }; + + private onParameterInputBlur = (): void => { + if (!this.isValueInput) { + this.clear(); + } + }; + + private onValueInputBlur = (): void => { + if (!this.isParameterInput) { + this.clear(); + } + }; + + clear(): void { + this.isActive = false; + this.activeItem = null; + this.currentValue = null; + } + + itemsListFormatter(item: any): string { + return item.name; + } + + onParameterNameChange(item: any): void { + if (item) { + this.isParameterInput = false; + this.isValueInput = true; + this.activeItem = item; + this.currentValue = ''; + setTimeout(() => this.valueInput.focus(), 0); + } + } + + onParameterValueChange(event: KeyboardEvent): void { + if (this.utils.isEnterPressed(event) && this.currentValue) { + this.parameters.push({ + id: this.currentId++, + name: this.activeItem.value, + label: this.activeItem.name, + value: this.currentValue, + isExclude: false + }); + this.currentValue = ''; + this.activeItem = null; + this.isValueInput = false; + this.updateValue(); + } + } + + removeParameter(event: MouseEvent, id: number): void { + this.parameters = this.parameters.filter(parameter => parameter.id !== id); + this.updateValue(); + event.stopPropagation(); + } + + updateValue() { + this.onChange(this.parameters); + } + + writeValue() { + } + + registerOnChange(callback: any): void { + this.onChange = callback; + } + + registerOnTouched() { + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less index f72183c..3f59a0d 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/variables.less @@ -20,7 +20,8 @@ @navbar-background-color: #323544; @h1-vertical-margin: 20px; @button-border-radius: 4px; -@input-border: 1px solid #CFD3D7; +@input-border-width: 1px; +@input-border: @input-border-width solid #CFD3D7; @button-border-radius: 4px; @input-group-addon-padding: 6px 0 6px 12px; @block-margin-top: 20px; @@ -33,6 +34,10 @@ @filters-panel-padding: 10px 0; @list-header-background-color: #F2F2F2; @checkbox-top: 4px; +@dropdown-min-width: 200px; +@dropdown-max-height: 500px; // TODO get rid of magic number, base on actual design +@input-height: 34px; +@input-padding: 10px; @fatal-color: #830A0A; @error-color: #E81D1D; @@ -100,6 +105,21 @@ left: 0; } +.dropdown-list-default { + line-height: 1; + border-radius: 2px; + font-size: 14px; + min-width: @dropdown-min-width; + background: #FFF; + color: #666; + border: 1px solid #CFD3D7; + padding: 5px 0; + margin: 2px 0 0; + text-align: left; + list-style: none; + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} + .dropdown-item-default { display: block; padding: 3px 20px; @@ -113,6 +133,6 @@ &:hover { color: #262626; text-decoration: none; - background-color: #f5f5f5; + background-color: #F5F5F5; } } http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/models/app-state.model.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/models/app-state.model.ts b/ambari-logsearch/ambari-logsearch-web/src/app/models/app-state.model.ts index 2995002..28ae763 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/models/app-state.model.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/models/app-state.model.ts @@ -22,6 +22,7 @@ export interface AppState { isLoginInProgress: boolean; isAuditLogsSet: boolean; isServiceLogsSet: boolean; + activeLogsType?: string; } export const initialState: AppState = { @@ -29,5 +30,6 @@ export const initialState: AppState = { isInitialLoading: false, isLoginInProgress: false, isAuditLogsSet: false, - isServiceLogsSet: false + isServiceLogsSet: false, + activeLogsType: 'serviceLogs' // TODO implement setting the parameter depending on user's navigation } http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts index 5b9e90d..38c063e 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/filtering.service.ts @@ -254,7 +254,8 @@ export class FilteringService { }, page: { defaultValue: 0 - } + }, + query: {} }; private filtersFormItems = Object.keys(this.filters).reduce((currentObject, key) => { @@ -298,7 +299,7 @@ export class FilteringService { }); } - private getStartTime(value: any, current: string): string { + private getStartTime = (value: any, current: string): string => { let time; if (value) { const endTime = moment(moment(current).valueOf()); @@ -317,9 +318,9 @@ export class FilteringService { } } return time ? time.toISOString() : ''; - } + }; - private getEndTime(value: any): string { + private getEndTime = (value: any): string => { let time; if (value) { switch (value.type) { @@ -337,16 +338,32 @@ export class FilteringService { } } return time ? time.toISOString() : ''; + }; + + private getQuery(isExclude: boolean): (value: any[]) => string { + return (value: any[]): string => { + let parameters; + if (value && value.length) { + parameters = value.filter(item => item.isExclude === isExclude).map(parameter => { + return { + [parameter.name]: parameter.value.replace(/\s/g, '+') + }; + }); + } + return parameters && parameters.length ? JSON.stringify(parameters) : ''; + } } readonly valueGetters = { - end_time: this.getEndTime.bind(this), - start_time: this.getStartTime.bind(this), - to: this.getEndTime.bind(this), - from: this.getStartTime.bind(this), + end_time: this.getEndTime, + start_time: this.getStartTime, + to: this.getEndTime, + from: this.getStartTime, sortType: value => value && value.type, sortBy: value => value && value.key, - page: value => value == null ? value : value.toString() + page: value => value == null ? value : value.toString(), + includeQuery: this.getQuery(false), + excludeQuery: this.getQuery(true) }; } http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts index 702deab..a90d099 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts @@ -50,7 +50,8 @@ export class LogsContainerService { hosts: ['host_name'], sorting: ['sortType', 'sortBy'], pageSize: ['pageSize'], - page: ['page'] + page: ['page'], + query: ['includeQuery', 'excludeQuery'] }; private readonly histogramFilters = { @@ -58,7 +59,8 @@ export class LogsContainerService { text: ['iMessage'], timeRange: ['to', 'from'], components: ['mustBe'], - levels: ['level'] + levels: ['level'], + query: ['includeQuery', 'excludeQuery'] }; readonly logsTypeMap = { http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/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 index 9f6cacd..0f90ba3 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts @@ -43,4 +43,8 @@ export class UtilsService { return valuesArray.join(','); } + isEnterPressed(event: KeyboardEvent): boolean { + return event.keyCode === 13; + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/a10e3887/ambari-logsearch/ambari-logsearch-web/yarn.lock ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/yarn.lock b/ambari-logsearch/ambari-logsearch-web/yarn.lock index 291b489..4883a15 100644 --- a/ambari-logsearch/ambari-logsearch-web/yarn.lock +++ b/ambari-logsearch/ambari-logsearch-web/yarn.lock @@ -3499,6 +3499,10 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +ng2-auto-complete@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/ng2-auto-complete/-/ng2-auto-complete-0.12.0.tgz#9a78c39c5012404e7bc8365c03815ab7f68cea3d" + ngx-bootstrap@^1.6.6: version "1.6.6" resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-1.6.6.tgz#0057141cfbdd7e8a50e81bda735fad8e95acb0dd"