[AMBARI-24887] [Log Search UI] The component filter dropdown does not select any item (#2599)
Change-Id: I9ef62c6e77e3d89d6548734793dc246a7342e80e
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
index 9921d41..f71b946 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
@@ -128,10 +128,10 @@
.filter((state: DataAvailabilityValues) => state === DataAvailabilityValues.AVAILABLE)
.first()
.subscribe(() => {
- this.filterDropdown.updateSelection(clusterSelection);
+ this.filterDropdown.writeValue(clusterSelection);
});
} else {
- this.filterDropdown.updateSelection(null);
+ this.filterDropdown.clearSelection();
}
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.ts
index af14925..d6f24e5 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.ts
@@ -19,7 +19,6 @@
import {Component, forwardRef} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {ListItem} from '@app/classes/list-item';
-import {UtilsService} from '@app/services/utils.service';
import {MenuButtonComponent} from '@app/components/menu-button/menu-button.component';
@Component({
@@ -36,65 +35,23 @@
})
export class FilterButtonComponent extends MenuButtonComponent implements ControlValueAccessor {
- private selectedItems: ListItem[] = [];
-
private onChange: (fn: any) => void;
- constructor(private utils: UtilsService) {
- super();
+ updateSelection(items: ListItem | ListItem[], callOnChange = true): void {
+ super.updateSelection(items);
+ if (callOnChange) {
+ this._onChange(this.selection);
+ }
}
- get selection(): ListItem[] {
- return this.selectedItems;
- }
-
- set selection(items: ListItem[]) {
- this.selectedItems = items;
+ private _onChange(value) {
if (this.onChange) {
- this.onChange(items);
- }
- }
-
- updateSelection(updates: ListItem | ListItem[]): void {
- if (updates && (!Array.isArray(updates) || updates.length)) {
- const items: ListItem[] = Array.isArray(updates) ? updates : [updates];
- if (this.isMultipleChoice) {
- items.forEach((item: ListItem) => {
- if (this.subItems && this.subItems.length) {
- const itemToUpdate: ListItem = this.subItems.find((option: ListItem) => this.utils.isEqual(option.value, item.value));
- if (itemToUpdate) {
- itemToUpdate.isChecked = item.isChecked;
- }
- }
- });
- } else {
- const selectedItem: ListItem = items.find((item: ListItem) => item.isChecked);
- this.subItems.forEach((item: ListItem) => {
- item.isChecked = !!selectedItem && this.utils.isEqual(item.value, selectedItem.value);
- });
- }
- } else {
- this.subItems.forEach((item: ListItem) => item.isChecked = false);
- }
- const checkedItems = this.subItems.filter((option: ListItem): boolean => option.isChecked);
- this.selection = checkedItems;
- this.selectItem.emit(checkedItems.map((option: ListItem): any => option.value));
- if (this.dropdownList) {
- this.dropdownList.doItemsCheck();
+ this.onChange(value);
}
}
writeValue(items: ListItem[]) {
- let listItems: ListItem[] = [];
- if (items && items.length) {
- listItems = items.map((item: ListItem) => {
- return {
- ...item,
- isChecked: true
- };
- });
- }
- this.updateSelection(listItems);
+ this.selection = items;
}
registerOnChange(callback: any): void {
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
index 65c22a4..62a1433 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
@@ -192,7 +192,7 @@
writeValue(filters: HomogeneousObject<LogIndexFilterComponentConfig[]>): void {
this.configs = filters;
- this.updateValue();
+ this.setCurrentConfig();
}
registerOnChange(callback: any): void {
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.spec.ts
index 4e77db5..2691273 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.spec.ts
@@ -40,6 +40,7 @@
import {AuthService} from '@app/services/auth.service';
import {MenuButtonComponent} from './menu-button.component';
+import { UtilsService } from '@app/services/utils.service';
describe('MenuButtonComponent', () => {
let component: MenuButtonComponent;
@@ -93,7 +94,8 @@
useValue: httpClient
},
LogsContainerService,
- AuthService
+ AuthService,
+ UtilsService
],
schemas: [NO_ERRORS_SCHEMA]
})
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.ts
index 788494c..faf2165 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/menu-button/menu-button.component.ts
@@ -19,6 +19,7 @@
import {Component, Input, Output, ViewChild, ElementRef, EventEmitter} from '@angular/core';
import {ListItem} from '@app/classes/list-item';
import {DropdownListComponent} from '@modules/shared/components/dropdown-list/dropdown-list.component';
+import {UtilsService} from '@app/services/utils.service';
@Component({
selector: 'menu-button',
@@ -46,13 +47,13 @@
subItems?: ListItem[];
@Input()
- isMultipleChoice: boolean = false;
+ isMultipleChoice = false;
@Input()
- hideCaret: boolean = false;
+ hideCaret = false;
@Input()
- isRightAlign: boolean = false;
+ isRightAlign = false;
@Input()
additionalLabelComponentSetter?: string;
@@ -61,10 +62,10 @@
badge: string;
@Input()
- caretClass: string = 'fa-caret-down';
+ caretClass = 'fa-caret-down';
@Input()
- useDropDownLocalFilter: boolean = false;
+ useDropDownLocalFilter = false;
/**
* The minimum time to handle a mousedown as a longclick. Default is 500 ms (0.5sec)
@@ -72,7 +73,7 @@
* @type {number}
*/
@Input()
- minLongClickDelay: number = 500;
+ minLongClickDelay = 500;
/**
* The maximum milliseconds to wait for longclick ends. The default is 0 which means no upper limit.
@@ -80,13 +81,13 @@
* @type {number}
*/
@Input()
- maxLongClickDelay: number = 0;
+ maxLongClickDelay = 0;
@Input()
- isDisabled: boolean = false;
+ isDisabled = false;
@Input()
- listClass: string = '';
+ listClass = '';
@Output()
buttonClick: EventEmitter<void> = new EventEmitter();
@@ -104,7 +105,7 @@
* Indicates if the dropdown list is open or not. So that we use internal state to display or hide the dropdown.
* @type {boolean}
*/
- private dropdownIsOpen: boolean = false;
+ private dropdownIsOpen = false;
get hasSubItems(): boolean {
return Boolean(this.subItems && this.subItems.length);
@@ -114,6 +115,26 @@
return this.hasSubItems && !this.hideCaret;
}
+ set selection(items: ListItem[] | null) {
+ const selectedItems = items ? (Array.isArray(items) ? items : [items]) : [];
+ this.subItems.forEach((subItem: ListItem) => {
+ const indexInSelection = this.findItemIndexInList(subItem, selectedItems);
+ subItem.isChecked = indexInSelection > -1;
+ });
+ this.refreshDropdownList();
+ }
+ get selection(): ListItem[] {
+ return this.subItems && this.subItems.filter((option: ListItem): boolean => option.isChecked);
+ }
+
+ constructor(private utils: UtilsService) {}
+
+ findItemIndexInList(item: ListItem, itemList: ListItem[] = this.subItems): number {
+ return itemList.findIndex((subItem) => (
+ item === subItem || this.utils.isEqual(item.value, subItem.value)
+ ));
+ }
+
/**
* Handling the click event on the component element.
* Two goal:
@@ -214,7 +235,7 @@
/**
* The main goal if this function is tho handle the item change event on the child dropdown list.
- * Should update the value and close the dropdown if it is not multiple choice type.
+ * Should update the value and close the dropdown.
* @param {ListItem} item The selected item(s) from the dropdown list.
*/
onDropdownItemChange(item: ListItem | ListItem[]) {
@@ -224,11 +245,22 @@
}
}
- updateSelection(item: ListItem | ListItem[]) {
- this.selectItem.emit(item);
+ refreshDropdownList() {
if (this.dropdownList) {
this.dropdownList.doItemsCheck();
}
}
+ updateSelection(item: ListItem | ListItem[]) {
+ const changes = Array.isArray(item) ? item : [item];
+ changes.forEach((change: ListItem): void => {
+ const subItemIndex = this.findItemIndexInList(change);
+ if (subItemIndex > -1) {
+ this.subItems[subItemIndex].isChecked = change.isChecked;
+ }
+ });
+ this.selectItem.emit(item);
+ this.refreshDropdownList();
+ }
+
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/pagination-controls/pagination-controls.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/pagination-controls/pagination-controls.component.ts
index 5f85da7..b476bf3 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/pagination-controls/pagination-controls.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/pagination-controls/pagination-controls.component.ts
@@ -54,9 +54,6 @@
if (this.isValidValue(newValue)) { // this is the last validation check
this.currentPage = newValue;
this.currentPageChange.emit(newValue);
- if (this.onChange) {
- this.onChange(newValue);
- }
} else {
throw new Error(`Invalid value ${newValue}. The currentPage should be between 0 and ${this.pagesCount}.`);
}
@@ -75,14 +72,14 @@
* The goal is to set the value to the first page... obviously to zero. It is just to have a centralized api for that.
*/
setFirstPage(): void {
- this.value = 0;
+ this._setValueByUserInput(0);
}
/**
* The goal is to set the value to the last page which is the pagesCount property anyway.
*/
setLastPage(): void {
- this.value = this.pagesCount - 1;
+ this._setValueByUserInput(this.pagesCount - 1);
}
/**
@@ -91,7 +88,7 @@
*/
setPreviousPage(): number {
if (this.hasPreviousPage()) {
- this.value -= 1;
+ this._setValueByUserInput(this.value - 1);
}
return this.value;
}
@@ -101,8 +98,8 @@
* @returns {number} The new value of the currentPage
*/
setNextPage(): number {
- if (this.hasNextPage()){
- this.value += 1;
+ if (this.hasNextPage()) {
+ this._setValueByUserInput(this.value + 1);
}
return this.value;
}
@@ -123,6 +120,17 @@
return this.pagesCount > 0 && this.value > 0;
}
+ private _setValueByUserInput(value) {
+ this.value = value;
+ this._onChange(this.value);
+ }
+
+ private _onChange(value) {
+ if (this.onChange) {
+ this.onChange(value);
+ }
+ }
+
writeValue(value: number) {
this.value = value;
}
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 62835bb..da33f60 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
@@ -97,7 +97,7 @@
* @type {boolean}
*/
@Input()
- updateValueImmediately: boolean = true;
+ updateValueImmediately = true;
@ViewChild('parameterInput')
parameterInputRef: ElementRef;
@@ -121,26 +121,22 @@
*/
parameters: SearchBoxParameterProcessed[] = [];
- private subscriptions: Subscription[] = [];
+ private onChange;
+
+ private destroyed$ = new Subject();
constructor(private utils: UtilsService) {}
ngOnInit(): void {
this.parameterInput = this.parameterInputRef.nativeElement;
this.valueInput = this.valueInputRef.nativeElement;
- this.subscriptions.push(
- this.parameterNameChangeSubject.subscribe(this.onParameterNameChange)
- );
- this.subscriptions.push(
- this.parameterAddSubject.subscribe(this.onParameterAdd)
- );
- this.subscriptions.push(
- this.updateValueSubject.subscribe(this.updateValue)
- );
+ this.parameterNameChangeSubject.takeUntil(this.destroyed$).subscribe(this.onParameterNameChange);
+ this.parameterAddSubject.takeUntil(this.destroyed$).subscribe(this.onParameterAdd);
+ this.updateValueSubject.takeUntil(this.destroyed$).subscribe(this.updateValue);
}
ngOnDestroy(): void {
- this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
+ this.destroyed$.next(true);
}
/**
@@ -152,8 +148,6 @@
this.itemsOptions[this.activeItem.value] : [];
}
- private onChange: (fn: any) => void;
-
@HostListener('click')
private onRootClick(): void {
if (!this.isActive) {
@@ -310,7 +304,7 @@
updateValue = (): void => {
this.currentValue = '';
if (this.onChange) {
- this.onChange(this.parameters.slice());
+ this.onChange([...this.parameters]);
}
}
@@ -331,8 +325,9 @@
}
writeValue(parameters: SearchBoxParameterProcessed[] = []): void {
- this.parameters = parameters.slice();
- this.updateValueSubject.next();
+ this.currentValue = '';
+ this.parameters = [...parameters];
+ // this.updateValueSubject.next();
}
registerOnChange(callback: any): void {
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
index e4e146f..3d031b2 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
@@ -61,9 +61,6 @@
set selection(newValue: TimeUnitListItem) {
this.timeRange = newValue;
- if (this.onChange) {
- this.onChange(newValue);
- }
this.setEndTime(this.logsFilteringUtilsService.getEndTimeMomentFromTimeUnitListItem(newValue, this.logsContainer.timeZone));
this.setStartTime(this.logsFilteringUtilsService.getStartTimeMomentFromTimeUnitListItem(
newValue, this.endTime, this.logsContainer.timeZone
@@ -80,6 +77,7 @@
setTimeRange(value: any, label: string): void {
this.selection = {label, value};
+ this._onChange(this.selection);
}
setCustomTimeRange(): void {
@@ -91,6 +89,13 @@
end: this.endTime
}
};
+ this._onChange(this.selection);
+ }
+
+ private _onChange(value: TimeUnitListItem): void {
+ if (this.onChange) {
+ this.onChange(value);
+ }
}
writeValue(selection: TimeUnitListItem): void {
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts
index 534b69d..fefd2e8 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts
@@ -89,7 +89,19 @@
constructor(protected utils: UtilsService) {}
- updateSelection(updates: ListItem | ListItem[]): void {
+ clearSelection(silent: boolean = false) {
+ let hasChange = false;
+ this.options.forEach((item: ListItem) => {
+ hasChange = hasChange || item.isChecked;
+ item.isChecked = false;
+ });
+ if (!silent && hasChange) {
+ this.selectItem.emit(this.isMultipleChoice ? [] : undefined);
+ }
+ }
+
+ updateSelection(updates: ListItem | ListItem[], callOnChange: boolean = true): boolean {
+ let hasChange = false;
if (updates && (!Array.isArray(updates) || updates.length)) {
const items: ListItem[] = Array.isArray(updates) ? updates : [updates];
if (this.isMultipleChoice) {
@@ -97,6 +109,7 @@
if (this.options && this.options.length) {
const itemToUpdate: ListItem = this.options.find((option: ListItem) => this.utils.isEqual(option.value, item.value));
if (itemToUpdate) {
+ hasChange = hasChange || itemToUpdate.isChecked !== item.isChecked;
itemToUpdate.isChecked = item.isChecked;
}
}
@@ -104,7 +117,9 @@
} else {
const selectedItem: ListItem = Array.isArray(updates) ? updates[0] : updates;
this.options.forEach((item: ListItem) => {
+ const checkedStateBefore = item.isChecked;
item.isChecked = this.utils.isEqual(item.value, selectedItem.value);
+ hasChange = hasChange || checkedStateBefore !== item.isChecked;
});
}
} else {
@@ -112,8 +127,11 @@
}
const checkedItems = this.options.filter((option: ListItem): boolean => option.isChecked);
this.selection = checkedItems;
- const selectedValues = checkedItems.map((option: ListItem): any => option.value);
- this.selectItem.emit(this.isMultipleChoice ? selectedValues : selectedValues.shift());
+ if (hasChange) {
+ const selectedValues = checkedItems.map((option: ListItem): any => option.value);
+ this.selectItem.emit(this.isMultipleChoice ? selectedValues : selectedValues.shift());
+ }
+ return hasChange;
}
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
index 651578a..3da860c 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
@@ -20,9 +20,9 @@
Component, OnChanges, AfterViewChecked, OnDestroy, SimpleChanges, Input, Output, EventEmitter,
ViewChildren, ViewContainerRef, QueryList, ChangeDetectorRef, ElementRef, ViewChild, OnInit
} from '@angular/core';
-import {Subscription} from 'rxjs/Subscription';
import {ListItem} from '@app/classes/list-item';
import {ComponentGeneratorService} from '@app/services/component-generator.service';
+import { Subject } from 'rxjs/Subject';
@Component({
selector: 'ul[data-component="dropdown-list"]',
@@ -77,7 +77,7 @@
private filterRegExp: RegExp;
- private subscriptions: Subscription[] = [];
+ private destroyed$ = new Subject();
constructor(
private componentGenerator: ComponentGeneratorService,
@@ -91,13 +91,11 @@
if (this.items.some((item: ListItem) => item.isChecked)) {
this.selectedItemChange.emit(this.items);
}
- this.subscriptions.push(
- this.selectedItemChange.subscribe(this.separateSelections)
- );
+ this.selectedItemChange.takeUntil(this.destroyed$).subscribe(this.separateSelections)
}
ngOnDestroy() {
- this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
+ this.destroyed$.next(true);
}
ngOnChanges(changes: SimpleChanges): void {
@@ -182,9 +180,6 @@
unSelectAll() {
this.items.forEach((item: ListItem) => {
item.isChecked = false;
- if (item.onSelect) {
- item.onSelect(...this.actionArguments);
- }
});
this.selectedItemChange.emit(this.items);
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts
index 6140e7d..669fcc9 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts
@@ -34,7 +34,7 @@
})
export class FilterDropdownComponent extends DropdownButtonComponent implements ControlValueAccessor {
- private onChange: (fn: any) => void;
+ private onChange;
get selection(): ListItem[] {
return this.selectedItems;
@@ -48,11 +48,22 @@
option.isChecked = Boolean(selectionItem);
});
}
+ }
+
+ private _onChange(value) {
if (this.onChange) {
- this.onChange(items);
+ this.onChange(value);
}
}
+ updateSelection(updates: ListItem | ListItem[], callOnChange: boolean = true): boolean {
+ const hasChange = super.updateSelection(updates);
+ if (hasChange && callOnChange) {
+ this._onChange(this.selection);
+ }
+ return hasChange;
+ }
+
writeValue(items: ListItem[]) {
this.selection = items || [];
}