You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/12/08 19:22:51 UTC
[12/21] ambari git commit: AMBARI-22610 Log Search UI: fixes for
search box autocomplete. (ababiichuk)
AMBARI-22610 Log Search UI: fixes for search box autocomplete. (ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/862b7d7b
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/862b7d7b
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/862b7d7b
Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 862b7d7b17e8e2ad165f548c4f9c328dd9151607
Parents: a9c3bf5
Author: ababiichuk <ab...@hortonworks.com>
Authored: Thu Dec 7 15:23:30 2017 +0200
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Thu Dec 7 19:21:59 2017 +0200
----------------------------------------------------------------------
.../ambari-logsearch-web/package.json | 3 +-
.../ambari-logsearch-web/src/app/app.module.ts | 8 +-
.../src/app/classes/filtering.ts | 2 +-
.../dropdown-list/dropdown-list.component.less | 24 ++-
.../filters-panel/filters-panel.component.html | 5 +-
.../filters-panel/filters-panel.component.ts | 23 +-
.../src/app/components/mixins.less | 17 +-
.../search-box/search-box.component.html | 28 ++-
.../search-box/search-box.component.less | 30 +--
.../search-box/search-box.component.spec.ts | 79 +++++++
.../search-box/search-box.component.ts | 214 ++++++++++---------
.../app/services/component-actions.service.ts | 9 +-
.../src/app/services/logs-container.service.ts | 22 --
ambari-logsearch/ambari-logsearch-web/yarn.lock | 6 +-
14 files changed, 259 insertions(+), 211 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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 2c6aa8d..b9ee179 100644
--- a/ambari-logsearch/ambari-logsearch-web/package.json
+++ b/ambari-logsearch/ambari-logsearch-web/package.json
@@ -34,8 +34,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",
+ "ngx-bootstrap": "^1.9.3",
"rxjs": "^5.4.3",
"zone.js": "^0.8.4"
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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 5e43582..b76de20 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
@@ -21,13 +21,12 @@ import {NgModule, CUSTOM_ELEMENTS_SCHEMA, Injector} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {HttpModule, Http, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy} from '@angular/http';
import {InMemoryBackendService} from 'angular-in-memory-web-api';
-import {AlertModule} from 'ngx-bootstrap';
+import {TypeaheadModule} from 'ngx-bootstrap';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
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';
@@ -150,7 +149,7 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR
FormsModule,
ReactiveFormsModule,
HttpModule,
- AlertModule.forRoot(),
+ TypeaheadModule.forRoot(),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
@@ -160,8 +159,7 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR
}),
StoreModule.provideStore(reducer),
MomentModule,
- MomentTimezoneModule,
- Ng2AutoCompleteModule
+ MomentTimezoneModule
],
providers: [
HttpClientService,
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/ambari-logsearch/ambari-logsearch-web/src/app/classes/filtering.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/filtering.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/filtering.ts
index d92dd41..3348969 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/filtering.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/filtering.ts
@@ -65,6 +65,6 @@ export interface SearchBoxParameterProcessed extends SearchBoxParameter {
}
export interface SearchBoxParameterTriggered {
- value: string;
+ item: ListItem;
isExclude: boolean;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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 674b195..d20bf75 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
@@ -22,20 +22,24 @@
max-height: @dropdown-max-height;
overflow-y: auto;
- .list-item-label {
+ > li {
.dropdown-item-default;
- label {
- margin-bottom: 0;
- cursor: pointer;
- }
+ .list-item-label {
+ .dropdown-item-child-default;
- input[type=checkbox]:checked + label:after {
- top: @checkbox-top;
- }
+ label {
+ margin-bottom: 0;
+ cursor: pointer;
+ }
+
+ input[type=checkbox]:checked + label:after {
+ top: @checkbox-top;
+ }
- .label-container {
- width: 100%;
+ .label-container {
+ width: 100%;
+ }
}
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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 440efde..f0cf3f4 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,8 +18,9 @@
<form [formGroup]="filtersForm">
<div class="form-inline filter-input-container col-md-8">
<search-box [parameterAddSubject]="queryParameterAdd" [parameterNameChangeSubject]="queryParameterNameChange"
- formControlName="query" [items]="searchBoxItemsTranslated" [itemsOptions]="options"
- [updateValueImmediately]="false" [updateValueSubject]="searchBoxValueUpdate" class="filter-input"></search-box>
+ class="filter-input" formControlName="query" [items]="searchBoxItems | async" [itemsOptions]="options"
+ [updateValueImmediately]="false" [updateValueSubject]="searchBoxValueUpdate"
+ defaultParameterName="log_message"></search-box>
<time-range-picker *ngIf="isFilterConditionDisplayed('timeRange')" formControlName="timeRange"
class="filter-input"></time-range-picker>
<timezone-picker class="filter-input"></timezone-picker>
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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 1717bd7..f9fe94b 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
@@ -24,7 +24,6 @@ import 'rxjs/add/observable/from';
import {FilterCondition, SearchBoxParameter, SearchBoxParameterTriggered} from '@app/classes/filtering';
import {ListItem} from '@app/classes/list-item';
import {LogsType} from '@app/classes/string';
-import {CommonEntry} from '@app/classes/models/common-entry';
import {LogsContainerService} from '@app/services/logs-container.service';
@Component({
@@ -63,38 +62,22 @@ export class FiltersPanelComponent implements OnChanges {
searchBoxItems: Observable<ListItem[]>;
- get searchBoxItemsTranslated(): CommonEntry[] {
- switch (this.logsType) {
- case 'auditLogs':
- return this.logsContainer.auditLogsColumnsTranslated;
- case 'serviceLogs':
- return this.logsContainer.serviceLogsColumnsTranslated;
- default:
- return [];
- }
- }
-
get filters(): {[key: string]: FilterCondition} {
return this.logsContainer.filters;
}
/**
* Object with options for search box parameter values
- * @returns {[key: string]: CommonEntry[]}
+ * @returns {[key: string]: ListItem[]}
*/
- get options(): {[key: string]: CommonEntry[]} {
+ get options(): {[key: string]: ListItem[]} {
return Object.keys(this.filters).filter((key: string): boolean => {
const condition = this.filters[key];
return Boolean(condition.fieldName && condition.options);
}).reduce((currentValue, currentKey) => {
const condition = this.filters[currentKey];
return Object.assign(currentValue, {
- [condition.fieldName]: condition.options.map((option: ListItem): CommonEntry => {
- return {
- name: option.value,
- value: option.value
- }
- })
+ [condition.fieldName]: condition.options
});
}, {});
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/ambari-logsearch/ambari-logsearch-web/src/app/components/mixins.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/mixins.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/mixins.less
index 0bf169d..a6e5616 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/mixins.less
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/mixins.less
@@ -95,21 +95,26 @@
.dropdown-item-default {
display: block;
- padding: 3px 20px;
- clear: both;
- font-weight: 400;
- line-height: 1.42857143;
color: #333;
- white-space: nowrap;
cursor: pointer;
- &:hover {
+ &.active > a, &:hover {
color: #262626;
text-decoration: none;
background-color: #F5F5F5;
}
}
+.dropdown-item-child-default {
+ display: block;
+ min-height: 24px;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: 400;
+ line-height: 1.42857143;
+ white-space: nowrap;
+}
+
.log-colors {
&.fatal {
color: @fatal-color;
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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
index 5ab9a69..786c130 100644
--- 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
@@ -15,26 +15,24 @@
limitations under the License.
-->
+<ng-template #listItemTemplate let-item="item">
+ {{item.label | translate}}
+</ng-template>
<label class="parameter-label" *ngFor="let parameter of parameters">
<span *ngIf="parameter.isExclude" class="fa fa-search-minus"></span>
{{parameter.label | translate}}:
<span class="parameter-value">{{parameter.value}}</span>
<span class="fa fa-times remove-parameter" (click)="removeParameter($event, parameter.id)"></span>
</label>
-<span class="active-parameter-label" *ngIf="isActive && activeItem">{{activeItem.name | translate}}:</span>
+<span class="active-parameter-label" *ngIf="isActive && activeItem">{{activeItem.label | translate}}:</span>
<div [ngClass]="{'search-item-container': true, 'active': isActive, 'value': isValueInput}">
- <span class="parameter-input-wrapper">
- <input #parameterInput auto-complete class="search-item-input parameter-input form-control"
- [(ngModel)]="currentValue" [source]="items" display-property-name="name"
- [list-formatter]="itemsListFormatter" [value-formatter]="itemsValueFormatter" [match-formatted]="true"
- (valueChanged)="changeParameterName({value: $event.value, isExclude: false})"
- (keyup)="onParameterKeyUp($event)">
- </span>
- <span [ngClass]="{'no-options': !activeItemValueOptions.length}">
- <input #valueInput auto-complete [(ngModel)]="currentValue" [source]="activeItemValueOptions"
- [list-formatter]="itemsListFormatter" [value-formatter]="itemsValueFormatter" [match-formatted]="true"
- (valueChanged)="onParameterValueChange($event.value)" (keydown)="onParameterValueKeyDown($event)"
- (keyup)="onParameterValueKeyUp($event)" class="search-item-input value-input form-control">
- </span>
- <div class="search-item-text">{{currentValue}}</div>
+ <input #parameterInput [(ngModel)]="currentValue" [typeahead]="items" typeaheadOptionField="value"
+ [typeaheadItemTemplate]="listItemTemplate" (typeaheadNoResults)="setParameterNameMatchFlag($event)"
+ (typeaheadOnSelect)="changeParameterName({item: $event.item, isExclude: false})"
+ (focus)="onParameterInputFocus()" (keyup)="onParameterKeyUp($event)"
+ class="search-item-input parameter-input form-control">
+ <input #valueInput [(ngModel)]="currentValue" [typeahead]="activeItemValueOptions" typeaheadOptionField="value"
+ [typeaheadItemTemplate]="listItemTemplate" (typeaheadNoResults)="setParameterValueMatchFlag($event)"
+ (typeaheadOnSelect)="onParameterValueChange($event.value)" (keydown)="onParameterValueKeyDown($event)"
+ (keyup)="onParameterValueKeyUp($event)" class="search-item-input value-input form-control">
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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
index 9deea92..80c0e5d 100644
--- 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
@@ -70,11 +70,6 @@
.collapsed-form-control;
}
- .search-item-text {
- visibility: hidden;
- padding: 0 @input-padding;
- }
-
&.active {
min-width: @dropdown-min-width;
@@ -87,35 +82,24 @@
}
&.value {
- .parameter-input-wrapper {
- /deep/ .ng2-auto-complete-wrapper {
- display: none;
- }
+ .parameter-input {
+ display: none;
}
.value-input {
width: 100%;
}
}
-
- .no-options {
- /deep/ .ng2-auto-complete {
- display: none;
- }
- }
}
- /deep/ .ng2-auto-complete {
- cursor: pointer;
+ /deep/ typeahead-container .dropdown-menu {
.dropdown-list-default;
- > ul {
- border: none;
+ > li {
+ .dropdown-item-default;
- li {
- border: none;
- background-color: initial;
- .dropdown-item-default;
+ > a{
+ .dropdown-item-child-default;
}
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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
index 72795a4..8d42c84 100644
--- 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
@@ -48,4 +48,83 @@ describe('SearchBoxComponent', () => {
it('should create component', () => {
expect(component).toBeTruthy();
});
+
+ describe('#activeItemValueOptions()', () => {
+ const cases = [
+ {
+ itemsOptions: null,
+ activeItem: {
+ value: 'v0'
+ },
+ result: [],
+ title: 'no options available'
+ },
+ {
+ itemsOptions: {
+ v1: [
+ {
+ value: 'v2'
+ }
+ ]
+ },
+ activeItem: null,
+ result: [],
+ title: 'no active item'
+ },
+ {
+ itemsOptions: {},
+ activeItem: {
+ value: 'v3'
+ },
+ result: [],
+ title: 'empty itemsOptions object'
+ },
+ {
+ itemsOptions: {
+ v4: [
+ {
+ value: 'v5'
+ }
+ ]
+ },
+ activeItem: {
+ value: 'v6'
+ },
+ result: [],
+ title: 'no options available for active item'
+ },
+ {
+ itemsOptions: {
+ v7: [
+ {
+ value: 'v8'
+ },
+ {
+ value: 'v9'
+ }
+ ]
+ },
+ activeItem: {
+ value: 'v7'
+ },
+ result: [
+ {
+ value: 'v8'
+ },
+ {
+ value: 'v9'
+ }
+ ],
+ title: 'options are available for active item'
+ }
+ ];
+
+ cases.forEach(test => {
+ it(test.title, () => {
+ component.itemsOptions = test.itemsOptions;
+ component.activeItem = test.activeItem;
+ expect(component.activeItemValueOptions).toEqual(test.result);
+ });
+ });
+ });
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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
index 64b8c36..b2136f4 100644
--- 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
@@ -16,11 +16,11 @@
* limitations under the License.
*/
-import {Component, OnInit, OnDestroy, Input, ViewChild, ElementRef, forwardRef} from '@angular/core';
+import {Component, OnInit, OnDestroy, HostListener, Input, ViewChild, ElementRef, forwardRef} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {Subject} from 'rxjs/Subject';
import {SearchBoxParameter, SearchBoxParameterProcessed, SearchBoxParameterTriggered} from '@app/classes/filtering';
-import {CommonEntry} from '@app/classes/models/common-entry';
+import {ListItem} from '@app/classes/list-item';
import {UtilsService} from '@app/services/utils.service';
@Component({
@@ -37,53 +37,65 @@ import {UtilsService} from '@app/services/utils.service';
})
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);
+ constructor(private utils: UtilsService) {
}
ngOnInit(): void {
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);
this.parameterNameChangeSubject.subscribe(this.onParameterNameChange);
this.parameterAddSubject.subscribe(this.onParameterAdd);
this.updateValueSubject.subscribe(this.updateValue);
}
ngOnDestroy(): void {
- 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);
this.parameterNameChangeSubject.unsubscribe();
this.parameterAddSubject.unsubscribe();
this.updateValueSubject.unsubscribe();
}
- private readonly messageParameterName: string = 'log_message';
-
private currentId: number = 0;
private isExclude: boolean = false;
+ /**
+ * Indicates whether search box is currently active
+ * @type {boolean}
+ */
isActive: boolean = false;
- isParameterInput: boolean = false;
-
+ /**
+ * Indicates whether search query parameter value is currently typed
+ * @type {boolean}
+ */
isValueInput: boolean = false;
currentValue: string;
+ /**
+ * Indicates whether there's no autocomplete matches in preset options for search query parameter name
+ * @type {boolean}
+ */
+ private noMatchingParameterName: boolean = true;
+
+ /**
+ * Indicates whether there's no autocomplete matches in preset options for search query parameter value
+ * @type {boolean}
+ */
+ private noMatchingParameterValue: boolean = true;
+
+ @Input()
+ items: ListItem[] = [];
+
@Input()
- items: CommonEntry[] = [];
+ itemsOptions: {[key: string]: ListItem[]} = {};
+ /**
+ * Name of parameter to be used if there are no matching values
+ * @type {string}
+ */
@Input()
- itemsOptions: {[key: string]: CommonEntry[]};
+ defaultParameterName?: string;
@Input()
parameterNameChangeSubject: Subject<SearchBoxParameterTriggered> = new Subject();
@@ -95,7 +107,8 @@ export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccess
updateValueSubject: Subject<void> = new Subject();
/**
- * Indicates whether form should receive updated value immediately after user adds new search parameter
+ * Indicates whether form should receive updated value immediately after user adds new search parameter, without
+ * explicit actions like pressing Submit button or Enter key
* @type {boolean}
*/
@Input()
@@ -107,65 +120,65 @@ export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccess
@ViewChild('valueInput')
valueInputRef: ElementRef;
- private rootElement: HTMLElement;
-
private parameterInput: HTMLInputElement;
private valueInput: HTMLInputElement;
- activeItem: CommonEntry | null = null;
+ /**
+ * Currently active search query parameter
+ * @type {ListItem | null}
+ */
+ activeItem: ListItem | null = null;
+ /**
+ * Search query parameters that are already specified by user
+ * @type {SearchBoxParameterProcessed[]}
+ */
parameters: SearchBoxParameterProcessed[] = [];
- get activeItemValueOptions(): CommonEntry[] {
+ /**
+ * Available options for value of currently active search query parameter
+ * @returns {ListItem[]}
+ */
+ get activeItemValueOptions(): ListItem[] {
return this.itemsOptions && this.activeItem && this.itemsOptions[this.activeItem.value] ?
this.itemsOptions[this.activeItem.value] : [];
}
private onChange: (fn: any) => void;
- private onRootClick = (): void => {
+ @HostListener('click')
+ private onRootClick(): void {
if (!this.isActive) {
this.parameterInput.focus();
}
- };
+ }
- private onRootKeyDown = (event: KeyboardEvent): void => {
+ @HostListener('keydown', ['$event'])
+ 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();
- }
+ @HostListener('blur')
+ private onRootBlur(): void {
+ this.clear();
};
- private onValueInputBlur = (): void => {
- if (!this.isParameterInput) {
- this.clear();
- }
- };
+ onParameterInputFocus(): void {
+ this.isActive = true;
+ }
private switchToParameterInput = (): void => {
- this.activeItem = null;
+ this.clear();
+ this.isActive = true;
this.isValueInput = false;
setTimeout(() => this.parameterInput.focus(), 0);
};
- private getItemByValue(name: string): CommonEntry {
- return this.items.find((field: CommonEntry): boolean => field.value === name);
- }
-
- private getItemByName(name: string): CommonEntry {
- return this.items.find((field: CommonEntry): boolean => field.name === name);
+ private getItemByValue(name: string): ListItem {
+ return this.items.find((field: ListItem): boolean => field.value === name);
}
clear(): void {
@@ -176,28 +189,17 @@ export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccess
this.valueInput.value = '';
}
- itemsListFormatter(item: CommonEntry): string {
- return item.name;
- }
-
- itemsValueFormatter(item: CommonEntry): string {
- return item.value;
- }
-
changeParameterName(options: SearchBoxParameterTriggered): void {
this.parameterNameChangeSubject.next(options);
}
onParameterNameChange = (options: SearchBoxParameterTriggered): void => {
- if (options.value) {
- this.activeItem = this.getItemByValue(options.value);
- this.isExclude = options.isExclude;
- this.isActive = true;
- this.isParameterInput = false;
- this.isValueInput = true;
- this.currentValue = '';
- setTimeout(() => this.valueInput.focus(), 0);
- }
+ this.activeItem = options.item.label ? options.item : this.getItemByValue(options.item.value);
+ this.isExclude = options.isExclude;
+ this.isActive = true;
+ this.isValueInput = true;
+ this.currentValue = '';
+ this.valueInput.focus();
};
onParameterValueKeyDown(event: KeyboardEvent): void {
@@ -207,59 +209,63 @@ export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccess
}
onParameterValueKeyUp(event: KeyboardEvent): void {
- if (this.utils.isEnterPressed(event) && this.currentValue) {
+ if (this.utils.isEnterPressed(event) && this.currentValue && this.noMatchingParameterValue) {
this.onParameterValueChange(this.currentValue);
}
}
onParameterValueChange(value: string): void {
- if (value) {
- this.parameters.push({
- id: this.currentId++,
- name: this.activeItem.value,
- label: this.activeItem.name,
- value: value,
- isExclude: this.isExclude
- });
- if (this.updateValueImmediately) {
- this.updateValueSubject.next();
- }
+ this.parameters.push({
+ id: this.currentId++,
+ name: this.activeItem.value,
+ label: this.activeItem.label,
+ value: value,
+ isExclude: this.isExclude
+ });
+ if (this.updateValueImmediately) {
+ this.updateValueSubject.next();
}
this.switchToParameterInput();
}
- onParameterAdd = (options: SearchBoxParameter): void => {
- const item = this.getItemByValue(options.name);
+ /**
+ * Adding the new parameter to search query
+ * @param parameter {SearchBoxParameter}
+ */
+ onParameterAdd = (parameter: SearchBoxParameter): void => {
+ const item = this.getItemByValue(parameter.name);
this.parameters.push({
id: this.currentId++,
- name: options.name,
- label: item.name,
- value: options.value,
- isExclude: options.isExclude
+ name: parameter.name,
+ label: item.label,
+ value: parameter.value,
+ isExclude: parameter.isExclude
});
if (this.updateValueImmediately) {
this.updateValueSubject.next();
}
+ this.switchToParameterInput();
};
- onParameterKeyUp = (event: KeyboardEvent): void => {
- if (this.utils.isEnterPressed(event) && this.currentValue) {
- const existingItem = this.getItemByName(this.currentValue);
- if (existingItem) {
- this.changeParameterName({
- value: this.currentValue,
- isExclude: false
- });
- } else {
+ onParameterKeyUp(event: KeyboardEvent): void {
+ if (this.utils.isEnterPressed(event)) {
+ if (!this.currentValue && !this.updateValueImmediately) {
+ this.updateValueSubject.next();
+ } else if (this.currentValue && this.noMatchingParameterName && this.defaultParameterName) {
this.parameterAddSubject.next({
- name: this.messageParameterName,
+ name: this.defaultParameterName,
value: this.currentValue,
isExclude: false
});
}
}
- };
+ }
+ /**
+ * Removing parameter from search query
+ * @param event {MouseEvent} - event that triggered this action
+ * @param id {number} - id of parameter
+ */
removeParameter(event: MouseEvent, id: number): void {
this.parameters = this.parameters.filter((parameter: SearchBoxParameterProcessed): boolean => parameter.id !== id);
if (this.updateValueImmediately) {
@@ -275,6 +281,22 @@ export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccess
}
};
+ /**
+ * Update flag that indicates presence of autocomplete matches in preset options for search query parameter name
+ * @param hasNoMatches {boolean}
+ */
+ setParameterNameMatchFlag(hasNoMatches: boolean): void {
+ this.noMatchingParameterName = hasNoMatches;
+ }
+
+ /**
+ * Update flag that indicates presence of autocomplete matches in preset options for search query parameter value
+ * @param hasNoMatches {boolean}
+ */
+ setParameterValueMatchFlag(hasNoMatches: boolean): void {
+ this.noMatchingParameterValue = hasNoMatches;
+ }
+
writeValue(parameters: SearchBoxParameterProcessed[] = []): void {
this.parameters = parameters;
this.updateValueSubject.next();
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
index 0fc9fde..51b0c0b 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/component-actions.service.ts
@@ -29,9 +29,8 @@ import {ListItem} from '@app/classes/list-item';
export class ComponentActionsService {
constructor(
- private appSettings: AppSettingsService, private tabsStorage: TabsService,
- private logsContainer: LogsContainerService,
- private authService: AuthService
+ private appSettings: AppSettingsService, private tabsStorage: TabsService, private authService: AuthService,
+ private logsContainer: LogsContainerService
) {
}
@@ -132,7 +131,9 @@ export class ComponentActionsService {
}
proceedWithExclude = (item: string): void => this.logsContainer.queryParameterNameChange.next({
- value: item,
+ item: {
+ value: item
+ },
isExclude: true
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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 4adf577..e754aa4 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
@@ -116,8 +116,6 @@ export class LogsContainerService {
this.loadLogs();
});
});
- this.auditLogsColumns.subscribe(this.getTranslationKeysSubscriber('auditLogsColumnsTranslated'));
- this.serviceLogsColumns.subscribe(this.getTranslationKeysSubscriber('serviceLogsColumnsTranslated'));
}
private readonly paginationOptions: string[] = ['10', '25', '50', '100'];
@@ -572,30 +570,10 @@ export class LogsContainerService {
}
}
- private getTranslationKeysSubscriber = (propertyName: string): (items: ListItem[]) => void => {
- return (items: ListItem[]): void => {
- const keys = items.map((item: ListItem): string => item.label);
- if (keys.length) {
- this.translate.get(keys).first().subscribe((translation: {[key: string]: string}): void => {
- this[propertyName] = items.map((item: ListItem): CommonEntry => {
- return {
- name: translation[item.label],
- value: item.value
- };
- });
- });
- }
- };
- };
-
auditLogsColumns: Observable<ListItem[]> = this.auditLogsFieldsStorage.getAll().map(this.columnsMapper);
- auditLogsColumnsTranslated: CommonEntry[] = [];
-
serviceLogsColumns: Observable<ListItem[]> = this.serviceLogsFieldsStorage.getAll().map(this.columnsMapper);
- serviceLogsColumnsTranslated: CommonEntry[] = [];
-
serviceLogs: Observable<ServiceLog[]> = Observable.combineLatest(this.serviceLogsStorage.getAll(), this.serviceLogsColumns).map(this.logsMapper);
auditLogs: Observable<AuditLog[]> = Observable.combineLatest(this.auditLogsStorage.getAll(), this.auditLogsColumns).map(this.logsMapper);
http://git-wip-us.apache.org/repos/asf/ambari/blob/862b7d7b/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 c005503..8eb2bbd 100644
--- a/ambari-logsearch/ambari-logsearch-web/yarn.lock
+++ b/ambari-logsearch/ambari-logsearch-web/yarn.lock
@@ -4152,11 +4152,7 @@ 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:
+ngx-bootstrap@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-1.9.3.tgz#28e75d14fb1beaee609383d7694de4eb3ba03b26"