AMBARI-21740 Log Search UI: implement multiple options select for filters. (ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b00da9b5 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b00da9b5 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b00da9b5 Branch: refs/heads/branch-feature-logsearch-ui Commit: b00da9b5e9e5a178b1c91af1c6a6855b42cbbf3a Parents: 01bcae9 Author: ababiichuk <ababiic...@hortonworks.com> Authored: Thu Aug 17 13:11:00 2017 +0300 Committer: ababiichuk <ababiic...@hortonworks.com> Committed: Thu Aug 17 13:11:00 2017 +0300 ---------------------------------------------------------------------- .../queries/service-logs-query-params.class.ts | 2 +- .../accordion-panel.component.html | 2 +- .../dropdown-button.component.html | 2 +- .../dropdown-button.component.ts | 23 ++++++--- .../dropdown-list/dropdown-list.component.html | 10 +++- .../dropdown-list/dropdown-list.component.less | 15 ++++++ .../dropdown-list/dropdown-list.component.ts | 3 ++ .../filter-button/filter-button.component.ts | 10 ++-- .../filter-dropdown.component.ts | 4 ++ .../filters-panel/filters-panel.component.html | 6 +-- .../logs-container.component.spec.ts | 3 ++ .../logs-container/logs-container.component.ts | 20 +++++--- .../logs-list/logs-list.component.html | 2 +- .../menu-button/menu-button.component.html | 2 +- .../menu-button/menu-button.component.ts | 3 ++ .../src/app/components/variables.less | 20 +++++++- .../src/app/models/app-state.model.ts | 6 ++- .../src/app/models/store.model.ts | 20 +++----- .../app/services/component-actions.service.ts | 6 ++- .../src/app/services/filtering.service.ts | 29 ++++------- .../src/app/services/mock-api-data.service.ts | 22 +++++--- .../src/app/services/utils.service.spec.ts | 53 ++++++++++++++++++++ .../src/app/services/utils.service.ts | 11 ++++ 23 files changed, 203 insertions(+), 71 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/classes/queries/service-logs-query-params.class.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/classes/queries/service-logs-query-params.class.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/classes/queries/service-logs-query-params.class.ts index 0914864..125b237 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/classes/queries/service-logs-query-params.class.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/classes/queries/service-logs-query-params.class.ts @@ -21,7 +21,7 @@ import {AuditLogsQueryParams} from '@app/classes/queries/audit-logs-query-params export class ServiceLogsQueryParams extends AuditLogsQueryParams { level?: string; host_name?: string; - component_name?: string; + mustBe?: string; file_name?: string; bundle_id?: string; hostList?: string; http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/accordion-panel/accordion-panel.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/accordion-panel/accordion-panel.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/accordion-panel/accordion-panel.component.html index b2ce3a0..1b134c3 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/accordion-panel/accordion-panel.component.html +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/accordion-panel/accordion-panel.component.html @@ -19,7 +19,7 @@ <div class="panel-body"> <ng-template [ngTemplateOutlet]="template"></ng-template> <div class="accordion-toggle"> - <span class="fa collapsed toggle-icon" data-toggle="collapse" [attr.data-target]="'#' + toggleId" aria-expanded="false"> </span> + <span class="fa collapsed toggle-icon" data-toggle="collapse" attr.data-target="#{{toggleId}}" aria-expanded="false"> </span> </div> </div> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.html index b777b52..a16b205 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.html +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.html @@ -21,5 +21,5 @@ <span *ngIf="!isMultipleChoice">{{selectedLabel | translate}}</span> <span class="caret"></span> </button> <ul data-component="dropdown-list" [ngClass]="{'dropdown-menu': true, 'dropdown-menu-right': isRightAlign}" - [items]="options" (selectedItemChange)="updateValue($event)"></ul> + [items]="options" [isMultipleChoice]="isMultipleChoice" (selectedItemChange)="updateValue($event)"></ul> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.ts index 029d87b..63103ee 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-button/dropdown-button.component.ts @@ -73,13 +73,22 @@ export class DropdownButtonComponent implements OnInit { this.selectedValue = value; } - updateValue(options: any) { - const value = options && options.value; - if (this.utils.valueHasChanged(this.value, value)) { - this.value = value; - this.selectedLabel = options.label; - if (this.action) { - this.actions[this.action](value, ...this.additionalArgs); + updateValue(eventOptions: any): void { + const value = eventOptions && eventOptions.value, + action = this.action && this.actions[this.action]; + if (this.isMultipleChoice) { + this.value = this.utils.updateMultiSelectValue(this.value, value, eventOptions.isChecked); + this.options.find(item => item.value === value).isChecked = eventOptions.isChecked; + if (action) { + action(this.options.filter(item => item.isChecked).map(item => item.value), ...this.additionalArgs); + } + } else { + if (this.utils.valueHasChanged(this.value, value)) { + this.value = value; + this.selectedLabel = eventOptions.label; + if (action) { + action(this.value, ...this.additionalArgs); + } } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.html index db4ee79..d9d1de0 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.html +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.html @@ -16,5 +16,13 @@ --> <li *ngFor="let item of items"> - <a href="#" (click)="changeSelectedItem({value: item.value, label: item.label})">{{item.label | translate}}</a> + <label class="list-item-label" *ngIf="isMultipleChoice"> + <input type="checkbox" [attr.id]="item.id || item.value" [attr.checked]="item.isChecked ? 'checked' : null" + (change)="changeSelectedItem({value: item.value, isChecked: $event.currentTarget.checked})"> + <label [attr.for]="item.id || item.value">{{item.label | translate}}</label> + </label> + <span class="list-item-label" *ngIf="!isMultipleChoice" + (click)="changeSelectedItem({value: item.value, label: item.label})"> + {{item.label | translate}} + </span> </li> http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.less b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.less index 0853883..804bf48 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.less +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.less @@ -16,7 +16,22 @@ * limitations under the License. */ +@import '../variables'; + :host { max-height: 500px; // TODO get rid of magic number, base on actual design overflow-y: auto; + + .list-item-label { + .dropdown-item-default; + + label { + margin-bottom: 0; + cursor: pointer; + } + + input[type=checkbox]:checked + label:after { + top: @checkbox-top; + } + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.ts index 3e9a445..555e4a8 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/dropdown-list/dropdown-list.component.ts @@ -31,6 +31,9 @@ export class DropdownListComponent { @Input() defaultAction: Function; + @Input() + isMultipleChoice?: boolean = false; + @Output() selectedItemChange: EventEmitter<any> = new EventEmitter(); http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-button/filter-button.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-button/filter-button.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-button/filter-button.component.ts index 2f8c969..9940d73 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-button/filter-button.component.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-button/filter-button.component.ts @@ -56,10 +56,14 @@ export class FilterButtonComponent extends MenuButtonComponent implements Contro this.onChange(newValue); } - updateValue(options: any) { + updateValue(options: any): void { const value = options && options.value; - if (this.utils.valueHasChanged(this.selectedValue, value)) { - this.value = value; + if (this.isMultipleChoice) { + this.value = this.utils.updateMultiSelectValue(this.value, value, options.isChecked); + } else { + if (this.utils.valueHasChanged(this.selectedValue, value)) { + this.value = value; + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-dropdown/filter-dropdown.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-dropdown/filter-dropdown.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-dropdown/filter-dropdown.component.ts index c414782..9e5a6f1 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-dropdown/filter-dropdown.component.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filter-dropdown/filter-dropdown.component.ts @@ -41,6 +41,10 @@ export class FilterDropdownComponent extends DropdownButtonComponent implements private onChange: (fn: any) => void; + get value(): any { + return this.selectedValue; + } + set value(newValue: any) { this.selectedValue = newValue; this.onChange(newValue); http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filters-panel/filters-panel.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filters-panel/filters-panel.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filters-panel/filters-panel.component.html index d2de5e2..4f751fd 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filters-panel/filters-panel.component.html +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/filters-panel/filters-panel.component.html @@ -18,7 +18,7 @@ <form class="col-md-12" [formGroup]="filtersForm"> <div class="form-inline filter-input-container col-md-8"> <filter-dropdown [label]="filters.clusters.label" formControlName="clusters" [options]="filters.clusters.options" - [defaultLabel]="filters.clusters.defaultLabel"></filter-dropdown> + [defaultLabel]="filters.clusters.defaultLabel" [isMultipleChoice]="true"></filter-dropdown> <filter-text-field [label]="filters.text.label" formControlName="text"></filter-text-field> <filter-dropdown formControlName="timeRange" [options]="filters.timeRange.options" @@ -35,9 +35,9 @@ </a> <filter-button formControlName="components" [label]="filters.components.label" [iconClass]="filters.components.iconClass" [subItems]="filters.components.options" - isRightAlign="true"></filter-button> + [isMultipleChoice]="true" isRightAlign="true"></filter-button> <filter-button formControlName="levels" [label]="filters.levels.label" [iconClass]="filters.levels.iconClass" - [subItems]="filters.levels.options" isRightAlign="true"></filter-button> + [subItems]="filters.levels.options" [isMultipleChoice]="true" isRightAlign="true"></filter-button> <menu-button label="filter.capture" iconClass="fa fa-caret-right"></menu-button> </div> </form> http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.spec.ts index 4d6509b..7b5169b 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.spec.ts @@ -20,6 +20,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; import {StoreModule} from '@ngrx/store'; import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service'; +import {AppStateService, appState} from '@app/services/storage/app-state.service'; import {ClustersService, clusters} from '@app/services/storage/clusters.service'; import {ComponentsService, components} from '@app/services/storage/components.service'; import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service'; @@ -51,6 +52,7 @@ describe('LogsContainerComponent', () => { imports: [ StoreModule.provideStore({ appSettings, + appState, clusters, components, auditLogs, @@ -66,6 +68,7 @@ describe('LogsContainerComponent', () => { useValue: httpClient }, AppSettingsService, + AppStateService, ClustersService, ComponentsService, AuditLogsService, http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.ts index 40e7d89..57a147c 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-container/logs-container.component.ts @@ -27,6 +27,7 @@ import {AuditLogsFieldsService} from '@app/services/storage/audit-logs-fields.se import {ServiceLogsService} from '@app/services/storage/service-logs.service'; import {ServiceLogsFieldsService} from '@app/services/storage/service-logs-fields.service'; import {ServiceLogsHistogramDataService} from '@app/services/storage/service-logs-histogram-data.service'; +import {AppStateService} from '@app/services/storage/app-state.service'; import {AuditLog} from '@app/models/audit-log.model'; import {ServiceLog} from '@app/models/service-log.model'; import {LogField} from '@app/models/log-field.model'; @@ -38,7 +39,7 @@ import {LogField} from '@app/models/log-field.model'; }) export class LogsContainerComponent implements OnInit { - constructor(private httpClient: HttpClientService, private auditLogsStorage: AuditLogsService, private auditLogsFieldsStorage: AuditLogsFieldsService, private serviceLogsStorage: ServiceLogsService, private serviceLogsFieldsStorage: ServiceLogsFieldsService, private serviceLogsHistogramStorage: ServiceLogsHistogramDataService, private filtering: FilteringService) { + constructor(private httpClient: HttpClientService, private auditLogsStorage: AuditLogsService, private auditLogsFieldsStorage: AuditLogsFieldsService, private serviceLogsStorage: ServiceLogsService, private serviceLogsFieldsStorage: ServiceLogsFieldsService, private serviceLogsHistogramStorage: ServiceLogsHistogramDataService, private appState: AppStateService, private filtering: FilteringService) { this.serviceLogsHistogramStorage.getAll().subscribe(data => { let histogramData = {}; data.forEach(type => { @@ -59,10 +60,11 @@ export class LogsContainerComponent implements OnInit { ngOnInit() { this.logsTypeMapObject = this.logsTypeMap[this.logsType]; + this.appState.getParameter(this.logsTypeMapObject.isSetFlag).subscribe(value => this.isLogsSet = value); this.availableColumns = this[this.logsTypeMapObject.fieldsModel].getAll().map(fields => { const availableFields = fields.filter(field => field.isAvailable), availableNames = availableFields.map(field => field.name); - if (availableNames.length) { + if (availableNames.length && !this.isLogsSet) { this.logs = this[this.logsTypeMapObject.logsModel].getAll().map(logs => logs.map(log => { let logObject = availableNames.reduce((obj, key) => Object.assign(obj, { [key]: log[key] @@ -72,11 +74,13 @@ export class LogsContainerComponent implements OnInit { } return logObject; })); + this.appState.setParameter(this.logsTypeMapObject.isSetFlag, true); } return availableFields.map(field => { return { value: field.name, - label: field.displayName || field.name + label: field.displayName || field.name, + isChecked: field.isDisplayed }; }); }); @@ -92,6 +96,8 @@ export class LogsContainerComponent implements OnInit { @Input() private logsType: string; + private isLogsSet: boolean = false; + logsTypeMapObject: any; totalCount: number = 0; @@ -100,7 +106,7 @@ export class LogsContainerComponent implements OnInit { clusters: ['clusters'], text: ['iMessage'], timeRange: ['end_time', 'start_time'], - components: ['component_name'], + components: ['mustBe'], levels: ['level'], sorting: ['sortType', 'sortBy'], pageSize: ['pageSize'], @@ -114,11 +120,13 @@ export class LogsContainerComponent implements OnInit { private readonly logsTypeMap = { auditLogs: { logsModel: 'auditLogsStorage', - fieldsModel: 'auditLogsFieldsStorage' + fieldsModel: 'auditLogsFieldsStorage', + isSetFlag: 'isAuditLogsSet' }, serviceLogs: { logsModel: 'serviceLogsStorage', - fieldsModel: 'serviceLogsFieldsStorage' + fieldsModel: 'serviceLogsFieldsStorage', + isSetFlag: 'isServiceLogsSet' } }; http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-list/logs-list.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-list/logs-list.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-list/logs-list.component.html index caae24e..23a62a4 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-list/logs-list.component.html +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/logs-list/logs-list.component.html @@ -36,7 +36,7 @@ </time> </div> <div class="col-md-6 log-content-wrapper"> - <div class="collapse log-actions" [attr.id]="'details-' + i"> + <div class="collapse log-actions" attr.id="details-{{i}}"> <span class="action-icon fa fa-search"></span> <span class="action-icon fa fa-external-link"></span> <span class="action-icon fa fa-bullseye"></span> http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.html index f18285f..a0f25ff 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.html +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.html @@ -23,5 +23,5 @@ <a *ngIf="label" (mousedown)="onMouseDown($event)" [ngClass]="labelClass" (mouseup)="onMouseUp($event)" (click)="$event.stopPropagation()">{{label | translate}}</a> <ul data-component="dropdown-list" *ngIf="hasSubItems" [items]="subItems" (selectedItemChange)="updateValue($event)" - [ngClass]="{'dropdown-menu': true, 'dropdown-menu-right': isRightAlign}"></ul> + [isMultipleChoice]="isMultipleChoice" [ngClass]="{'dropdown-menu': true, 'dropdown-menu-right': isRightAlign}"></ul> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.ts index d1baedc..0b58ce1 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/menu-button/menu-button.component.ts @@ -49,6 +49,9 @@ export class MenuButtonComponent { subItems?: any[]; @Input() + isMultipleChoice?: boolean = false; + + @Input() hideCaret?: boolean = false; @Input() http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/components/variables.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/variables.less b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/variables.less index 7715876..0d739a1 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/components/variables.less +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/components/variables.less @@ -22,7 +22,7 @@ @button-border-radius: 4px; @input-border: 1px solid #CFD3D7; @button-border-radius: 4px; -@input-group-addon-padding: 6px 12px; +@input-group-addon-padding: 6px 0 6px 12px; @block-margin-top: 20px; @link-color: #1491C1; @link-hover-color: #23527C; @@ -32,6 +32,7 @@ @filters-panel-background-color: #FFF; @filters-panel-padding: 10px 0; @list-header-background-color: #F2F2F2; +@checkbox-top: 4px; @fatal-color: #830A0A; @error-color: #E81D1D; @@ -96,3 +97,20 @@ bottom: 0; left: 0; } + +.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 { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/models/app-state.model.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/models/app-state.model.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/models/app-state.model.ts index 028c10d..2995002 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/models/app-state.model.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/models/app-state.model.ts @@ -20,10 +20,14 @@ export interface AppState { isAuthorized: boolean; isInitialLoading: boolean; isLoginInProgress: boolean; + isAuditLogsSet: boolean; + isServiceLogsSet: boolean; } export const initialState: AppState = { isAuthorized: false, isInitialLoading: false, - isLoginInProgress: false + isLoginInProgress: false, + isAuditLogsSet: false, + isServiceLogsSet: false } http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/models/store.model.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/models/store.model.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/models/store.model.ts index 13a1e68..8d71174 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/models/store.model.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/models/store.model.ts @@ -35,7 +35,7 @@ export const storeActions = { 'ARRAY.DELETE.PRIMITIVE': 'DELETE_PRIMITIVE', 'ARRAY.DELETE.OBJECT': 'DELETE_OBJECT', 'ARRAY.CLEAR': 'CLEAR', - 'ARRAY.UPDATE.OBJECT': 'UPDATE_OBJECT', + 'ARRAY.MAP': 'MAP', 'OBJECT.SET': 'SET' }; @@ -106,13 +106,11 @@ export class CollectionModelService extends ModelService { }); } - updateObjectInstance(key: string, value: any, keyToModify: string, modifier: (value: any) => {}): void { + mapCollection(modifier: (item: any) => {}): void { this.store.dispatch({ - type: `${storeActions['ARRAY.UPDATE.OBJECT']}_${this.modelName}`, + type: `${storeActions['ARRAY.MAP']}_${this.modelName}`, payload: { - selector: item => item[key] === value, - key: keyToModify, - modifier: (currentValue) => modifier(currentValue) + modifier: modifier } }); } @@ -151,14 +149,8 @@ export function getCollectionReducer(modelName: string, defaultState: any = []): return state.filter(item => item !== action.payload); case `${storeActions['ARRAY.CLEAR']}_${modelName}`: return []; - case `${storeActions['ARRAY.UPDATE.OBJECT']}_${modelName}`: - const payload = action.payload; - let newState = state.slice(), - item = newState.find(payload.selector); - if (item) { - item[payload.key] = payload.modifier(item[payload.key]); - } - return newState; + case `${storeActions['ARRAY.MAP']}_${modelName}`: + return state.map(action.payload.modifier); default: return state; } http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/services/component-actions.service.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/component-actions.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/component-actions.service.ts index f79ba45..a8235fa 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/component-actions.service.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/component-actions.service.ts @@ -44,8 +44,10 @@ export class ComponentActionsService { this.appSettings.setParameter('timeZone', timeZone); } - updateSelectedColumns(columnName: string, model: CollectionModelService): void { - model.updateObjectInstance('name', columnName, 'isDisplayed', currentValue => !currentValue); + updateSelectedColumns(columnNames: string[], model: CollectionModelService): void { + model.mapCollection(item => Object.assign({}, item, { + isDisplayed: columnNames.indexOf(item.name) > -1 + })); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/services/filtering.service.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/filtering.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/filtering.service.ts index 009b263..9a589cc 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/filtering.service.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/filtering.service.ts @@ -29,8 +29,12 @@ export class FilteringService { constructor(private appSettings: AppSettingsService, private clustersStorage: ClustersService, private componentsStorage: ComponentsService, private utils: UtilsService) { this.appSettings.getParameter('timeZone').subscribe(value => this.timeZone = value || this.defaultTimeZone); - this.clustersStorage.getAll().subscribe(clusters => this.filters.clusters.options = [...this.filters.clusters.options, ...clusters.map(this.getListItem)]); - this.componentsStorage.getAll().subscribe(components => this.filters.components.options = [...this.filters.components.options, ...components.map(this.getListItem)]); + this.clustersStorage.getAll().subscribe(clusters => { + this.filters.clusters.options = [...this.filters.clusters.options, ...clusters.map(this.getListItem)]; + }); + this.componentsStorage.getAll().subscribe(components => { + this.filters.components.options = [...this.filters.components.options, ...components.map(this.getListItem)]; + }); } private getListItem(name: string): any { @@ -49,14 +53,8 @@ export class FilteringService { filters = { clusters: { label: 'filter.clusters', - options: [ - { - label: 'filter.all', - value: '' - } - ], - defaultValue: '', - defaultLabel: 'filter.all' + options: [], + defaultValue: '' }, text: { label: 'filter.message', @@ -141,12 +139,7 @@ export class FilteringService { components: { label: 'filter.components', iconClass: 'fa fa-cubes', - options: [ - { - label: 'filter.all', - value: '' - } - ], + options: [], defaultValue: '' }, levels: { @@ -154,10 +147,6 @@ export class FilteringService { iconClass: 'fa fa-sort-amount-asc', options: [ { - label: 'filter.all', - value: '' - }, - { label: 'levels.fatal', value: 'FATAL' }, http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts index 985a0bf..2289f09 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts @@ -37,13 +37,16 @@ export class mockApiDataService implements InMemoryDbService { totalCountKey: 'totalCount', filters: { clusters: { - key: 'cluster' + key: 'cluster', + isValuesList: true }, - component_name: { - key: 'type' + mustBe: { + key: 'type', + isValuesList: true }, level: { - key: 'level' + key: 'level', + isValuesList: true }, iMessage: { key: 'log_message', @@ -110,11 +113,14 @@ export class mockApiDataService implements InMemoryDbService { let filteredCollection = collection.filter(item => { let result = true; query.paramsMap.forEach((value, key) => { - const paramValue = decodeURIComponent(value[0]), // TODO implement multiple conditions - paramFilter = filterMapItem.filters[key]; + const paramValue = decodeURIComponent(value[0]), + paramFilter = filterMapItem.filters[key], + paramValuesList = paramFilter && paramFilter.isValuesList && paramValue ? paramValue.split(',') : [], + currentValue = paramFilter && item[paramFilter.key]; if (paramFilter && - ((paramFilter.filterFunction && !paramFilter.filterFunction(item[paramFilter.key], paramValue)) || - (!paramFilter.filterFunction && item[paramFilter.key] !== paramValue))) { + ((paramFilter.filterFunction && !paramFilter.filterFunction(currentValue, paramValue)) || + (!paramFilter.filterFunction && !paramFilter.isValuesList && currentValue !== paramValue) || + (!paramFilter.filterFunction && paramFilter.isValuesList && paramValuesList.indexOf(currentValue) === -1))) { result = false; } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.spec.ts index a93eee5..a4a0cf8 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.spec.ts @@ -30,4 +30,57 @@ describe('UtilsService', () => { it('should create service', inject([UtilsService], (service: UtilsService) => { expect(service).toBeTruthy(); })); + + describe('#updateMultiSelectValue()', () => { + const cases = [ + { + currentValue: '', + value: 'v0', + isChecked: true, + result: 'v0', + title: 'check; no checked items before' + }, + { + currentValue: 'v1,v2', + value: 'v3', + isChecked: true, + result: 'v1,v2,v3', + title: 'check' + }, + { + currentValue: 'v4,v5', + value: 'v4', + isChecked: false, + result: 'v5', + title: 'uncheck' + }, + { + currentValue: 'v6,v7', + value: 'v6', + isChecked: true, + result: 'v6,v7', + title: 'avoid repeating check action' + }, + { + currentValue: 'v8,v9', + value: 'v10', + isChecked: false, + result: 'v8,v9', + title: 'avoid repeating uncheck action' + }, + { + currentValue: 'v11', + value: 'v11', + isChecked: false, + result: '', + title: 'uncheck last item' + } + ]; + + cases.forEach(test => { + it(test.title, inject([UtilsService], (service: UtilsService) => { + expect(service.updateMultiSelectValue(test.currentValue, test.value, test.isChecked)).toEqual(test.result); + })); + }); + }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/b00da9b5/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.ts index 7180ebb..2deff9e 100644 --- a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.ts +++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/utils.service.ts @@ -33,6 +33,17 @@ export class UtilsService { } } + updateMultiSelectValue(currentValue: string, value: string, isChecked: boolean): string { + let valuesArray = currentValue ? currentValue.split(',') : [], + valuePosition = valuesArray.indexOf(value); + if (isChecked && valuePosition === -1) { + valuesArray.push(value); + } else if (!isChecked && valuePosition > -1) { + valuesArray.splice(valuePosition, 1); + } + return valuesArray.join(','); + } + getTimeZoneLabel(timeZone) { return `${timeZone} (${moment.tz(timeZone).format('Z')})`; }