http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties b/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties index db8a0a2..3a0f460 100755 --- a/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties +++ b/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties @@ -12,49 +12,27 @@ # 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. - -#logsearch.solr.url=http://host:port/solr -logsearch.solr.url= - -#Solr Core +logsearch.solr.zk_connect_string=localhost:2181 logsearch.solr.collection.service.logs=hadoop_logs -#logsearch.solr.collection.service.logs=ranger_audits +logsearch.service.logs.split.interval.mins=15 +logsearch.collection.service.logs.numshards=3 +logsearch.collection.service.logs.replication.factor=2 +logsearch.solr.audit.logs.zk_connect_string=localhost:2181 +logsearch.solr.collection.audit.logs=audit_logs +logsearch.audit.logs.split.interval.mins=15 +logsearch.collection.audit.logs.numshards=2 +logsearch.collection.audit.logs.replication.factor=2 +logsearch.solr.config_set.folder=${LOGSEARCH_SERVER_RELATIVE_LOCATION:}src/main/configsets +logsearch.solr.audit.logs.config_set.folder=${LOGSEARCH_SERVER_RELATIVE_LOCATION:}src/main/configsets logsearch.solr.collection.history=history -logsearch.service.logs.split.interval.mins=none -logsearch.collection.service.logs.numshards=1 -logsearch.collection.service.logs.replication.factor=1 - -#If set, metrics will be sent to Ambari -#logsearch.solr.metrics.collector.hosts=example.com -logsearch.solr.metrics.collector.hosts= -logsearch.solr.audit.logs.url= -#logsearch.solr.collection.audit.logs=collection_name -logsearch.solr.collection.audit.logs=ranger_audits -logsearch.audit.logs.split.interval.mins=none -logsearch.collection.audit.logs.numshards=1 -logsearch.collection.audit.logs.replication.factor=1 - -#Authentication settings -#Note: Simple will be supported only if file ,ldap and external_auth all three are disabled. +logsearch.solr.history.config.name=history +logsearch.collection.history.replication.factor=1 logsearch.auth.file.enable=true +logsearch.login.credentials.file=user_pass.json + logsearch.auth.ldap.enable=false logsearch.auth.simple.enable=false logsearch.auth.external_auth.enable=false -logsearch.auth.external_auth.host_url=http://ip:port -logsearch.auth.external_auth.login_url=/api/v1/users/$USERNAME/privileges?fields=* -#Note: Use comma(,) for separation of multiple roles -logsearch.roles.allowed=AMBARI.ADMINISTRATOR - -logsearch.http.port=61888 -logsearch.https.port=61889 logsearch.protocol=http - -logsearch.solr.kerberos.enable=false -logsearch.solr.jaas.file=/usr/lib/ambari-logsearch-portal/logsearch_solr_jaas.conf - -#portal Kerberos -logsearch.spnego.kerberos.enabled=false -logsearch.spnego.kerberos.keytab= -logsearch.spnego.kerberos.principal= -logsearch.spnego.kerberos.host= \ No newline at end of file +logsearch.config.zk_connect_string=localhost:2181 \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/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 37cd869..5e43582 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts @@ -34,7 +34,6 @@ 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'; -import {FilteringService} from '@app/services/filtering.service'; import {UtilsService} from '@app/services/utils.service'; import {LogsContainerService} from '@app/services/logs-container.service'; import {ComponentGeneratorService} from '@app/services/component-generator.service'; @@ -54,6 +53,7 @@ import {ComponentsService} from '@app/services/storage/components.service'; import {ServiceLogsFieldsService} from '@app/services/storage/service-logs-fields.service'; import {AuditLogsFieldsService} from '@app/services/storage/audit-logs-fields.service'; import {TabsService} from '@app/services/storage/tabs.service'; +import {AuthService} from '@app/services/auth.service'; import {reducer} from '@app/services/storage/reducers.service'; import {AppComponent} from '@app/components/app.component'; @@ -67,12 +67,14 @@ import {DropdownListComponent} from '@app/components/dropdown-list/dropdown-list import {FilterButtonComponent} from '@app/components/filter-button/filter-button.component'; import {AccordionPanelComponent} from '@app/components/accordion-panel/accordion-panel.component'; import {CollapsiblePanelComponent} from '@app/components/collapsible-panel/collapsible-panel.component'; -import {LogsListComponent} from '@app/components/logs-list/logs-list.component'; +import {LogMessageComponent} from '@app/components/log-message/log-message.component'; +import {LogLevelComponent} from '@app/components/log-level/log-level.component'; import {DropdownButtonComponent} from '@app/components/dropdown-button/dropdown-button.component'; import {PaginationComponent} from '@app/components/pagination/pagination.component'; import {PaginationControlsComponent} from '@app/components/pagination-controls/pagination-controls.component'; import {TimeHistogramComponent} from '@app/components/time-histogram/time-histogram.component'; import {LogsContainerComponent} from '@app/components/logs-container/logs-container.component'; +import {ActionMenuComponent} from "@app/components/action-menu/action-menu.component"; 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'; @@ -82,6 +84,8 @@ import {DatePickerComponent} from '@app/components/date-picker/date-picker.compo import {LogContextComponent} from '@app/components/log-context/log-context.component'; import {LogFileEntryComponent} from '@app/components/log-file-entry/log-file-entry.component'; import {TabsComponent} from '@app/components/tabs/tabs.component'; +import {ServiceLogsTableComponent} from '@app/components/service-logs-table/service-logs-table.component'; +import {AuditLogsTableComponent} from '@app/components/audit-logs-table/audit-logs-table.component'; import {TimeZoneAbbrPipe} from '@app/pipes/timezone-abbr.pipe'; import {TimerSecondsPipe} from '@app/pipes/timer-seconds.pipe'; @@ -119,12 +123,14 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR FilterButtonComponent, AccordionPanelComponent, CollapsiblePanelComponent, - LogsListComponent, + LogLevelComponent, + LogMessageComponent, DropdownButtonComponent, PaginationComponent, PaginationControlsComponent, TimeHistogramComponent, LogsContainerComponent, + ActionMenuComponent, ModalComponent, TimeZonePickerComponent, NodeBarComponent, @@ -134,6 +140,8 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR LogContextComponent, LogFileEntryComponent, TabsComponent, + ServiceLogsTableComponent, + AuditLogsTableComponent, TimeZoneAbbrPipe, TimerSecondsPipe ], @@ -158,7 +166,6 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR providers: [ HttpClientService, ComponentActionsService, - FilteringService, UtilsService, LogsContainerService, ComponentGeneratorService, @@ -181,7 +188,8 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR provide: XHRBackend, useFactory: getXHRBackend, deps: [Injector, BrowserXhr, XSRFStrategy, ResponseOptions] - } + }, + AuthService ], bootstrap: [AppComponent], entryComponents: [NodeBarComponent], http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts new file mode 100644 index 0000000..05f80a7 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts @@ -0,0 +1,61 @@ +/** + * 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 {LogsTableComponent} from './logs-table-component'; + +describe('LogsTableComponent', () => { + let component; + + beforeEach(() => { + component = new LogsTableComponent(); + }); + + describe('#isColumnDisplayed()', () => { + const cases = [ + { + name: 'v1', + result: true, + title: 'column is displayed' + }, + { + name: 'l1', + result: false, + title: 'column is not displayed' + } + ]; + + beforeEach(() => { + component.displayedColumns = [ + { + label: 'l0', + value: 'v0' + }, + { + label: 'l1', + value: 'v1' + } + ]; + }); + + cases.forEach(test => { + it(test.title, () => { + expect(component.isColumnDisplayed(test.name)).toEqual(test.result); + }); + }); + }); +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts new file mode 100644 index 0000000..0b8866a --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts @@ -0,0 +1,51 @@ +/** + * 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 {OnChanges, SimpleChanges, Input} from '@angular/core'; +import {FormGroup} from '@angular/forms'; +import {ListItem} from '@app/classes/list-item'; +import {ServiceLog} from '@app/classes/models/service-log'; +import {AuditLog} from '@app/classes/models/audit-log'; + +export class LogsTableComponent implements OnChanges { + + ngOnChanges(changes: SimpleChanges) { + if (changes.hasOwnProperty('columns')) { + this.displayedColumns = this.columns.filter((column: ListItem): boolean => column.isChecked); + } + } + + @Input() + logs: ServiceLog[] | AuditLog[] = []; + + @Input() + columns: ListItem[] = []; + + @Input() + filtersForm: FormGroup; + + @Input() + totalCount: number = 0; + + displayedColumns: ListItem[] = []; + + isColumnDisplayed(key: string): boolean { + return this.displayedColumns.some((column: ListItem): boolean => column.value === key); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/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 dde144b..2a7205f 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/filtering.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/filtering.ts @@ -16,354 +16,37 @@ * limitations under the License. */ -import {FormGroup, FormControl} from '@angular/forms'; +import {Moment, unitOfTime} from 'moment'; import {ListItem} from '@app/classes/list-item'; export interface TimeUnit { type: 'CURRENT' | 'LAST' | 'PAST'; - unit: 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'Y'; + unit: unitOfTime.DurationConstructor; interval?: number; } +export interface CustomTimeRange { + type: 'CUSTOM'; + start?: Moment; + end?: Moment; +} + +export interface SortingConditions { + key: string; + type: 'asc' | 'desc'; +} + export interface TimeUnitListItem extends ListItem { - value: TimeUnit; + value: TimeUnit | CustomTimeRange; +} + +export interface SortingListItem extends ListItem { + value: SortingConditions; } export interface FilterCondition { label?: string; options?: (ListItem | TimeUnitListItem[])[]; - defaultValue?: string | number | {[key: string]: any}; - defaultLabel?: string; + defaultSelection?: ListItem | ListItem[] | number; iconClass?: string; } - -const paginationOptions: string[] = ['10', '25', '50', '100']; - -export const filters: {[key: string]: FilterCondition} = { - clusters: { - label: 'filter.clusters', - options: [], - defaultValue: '' - }, - timeRange: { - options: [ - [ - { - label: 'filter.timeRange.7d', - value: { - type: 'LAST', - unit: 'd', - interval: 7 - } - }, - { - label: 'filter.timeRange.30d', - value: { - type: 'LAST', - unit: 'd', - interval: 30 - } - }, - { - label: 'filter.timeRange.60d', - value: { - type: 'LAST', - unit: 'd', - interval: 60 - } - }, - { - label: 'filter.timeRange.90d', - value: { - type: 'LAST', - unit: 'd', - interval: 90 - } - }, - { - label: 'filter.timeRange.6m', - value: { - type: 'LAST', - unit: 'M', - interval: 6 - } - }, - { - label: 'filter.timeRange.1y', - value: { - type: 'LAST', - unit: 'Y', - interval: 1 - } - }, - { - label: 'filter.timeRange.2y', - value: { - type: 'LAST', - unit: 'Y', - interval: 2 - } - }, - { - label: 'filter.timeRange.5y', - value: { - type: 'LAST', - unit: 'Y', - interval: 5 - } - } - ], - [ - { - label: 'filter.timeRange.yesterday', - value: { - type: 'PAST', - unit: 'd' - } - }, - // TODO implement time range calculation - /* - { - label: 'filter.timeRange.beforeYesterday', - value: { - type: 'PAST', - unit: 'd' - } - }, - { - label: 'filter.timeRange.thisDayLastWeek', - value: { - type: 'PAST', - unit: 'd' - } - }, - */ - { - label: 'filter.timeRange.previousWeek', - value: { - type: 'PAST', - unit: 'w' - } - }, - { - label: 'filter.timeRange.previousMonth', - value: { - type: 'PAST', - unit: 'M' - } - }, - { - label: 'filter.timeRange.previousYear', - value: { - type: 'PAST', - unit: 'Y' - } - } - ], - [ - { - label: 'filter.timeRange.today', - value: { - type: 'CURRENT', - unit: 'd' - } - }, - { - label: 'filter.timeRange.thisWeek', - value: { - type: 'CURRENT', - unit: 'w' - } - }, - { - label: 'filter.timeRange.thisMonth', - value: { - type: 'CURRENT', - unit: 'M' - } - }, - { - label: 'filter.timeRange.thisYear', - value: { - type: 'CURRENT', - unit: 'Y' - } - } - ], - [ - { - label: 'filter.timeRange.5min', - value: { - type: 'LAST', - unit: 'm', - interval: 5 - } - }, - { - label: 'filter.timeRange.15min', - value: { - type: 'LAST', - unit: 'm', - interval: 15 - } - }, - { - label: 'filter.timeRange.30min', - value: { - type: 'LAST', - unit: 'm', - interval: 30 - } - }, - { - label: 'filter.timeRange.1hr', - value: { - type: 'LAST', - unit: 'h', - interval: 1 - } - }, - { - label: 'filter.timeRange.3hr', - value: { - type: 'LAST', - unit: 'h', - interval: 3 - } - }, - { - label: 'filter.timeRange.6hr', - value: { - type: 'LAST', - unit: 'h', - interval: 6 - } - }, - { - label: 'filter.timeRange.12hr', - value: { - type: 'LAST', - unit: 'h', - interval: 12 - } - }, - { - label: 'filter.timeRange.24hr', - value: { - type: 'LAST', - unit: 'h', - interval: 24 - } - }, - ] - ], - defaultValue: { - type: 'LAST', - unit: 'h', - interval: 1 - }, - defaultLabel: 'filter.timeRange.1hr' - }, - components: { - label: 'filter.components', - iconClass: 'fa fa-cubes', - options: [], - defaultValue: '' - }, - levels: { - label: 'filter.levels', - iconClass: 'fa fa-sort-amount-asc', - options: [ - { - label: 'levels.fatal', - value: 'FATAL' - }, - { - label: 'levels.error', - value: 'ERROR' - }, - { - label: 'levels.warn', - value: 'WARN' - }, - { - label: 'levels.info', - value: 'INFO' - }, - { - label: 'levels.debug', - value: 'DEBUG' - }, - { - label: 'levels.trace', - value: 'TRACE' - }, - { - label: 'levels.unknown', - value: 'UNKNOWN' - } - ], - defaultValue: '' - }, - hosts: { - label: 'filter.hosts', - iconClass: 'fa fa-server', - options: [], - defaultValue: '' - }, - sorting: { - label: 'sorting.title', - options: [ - { - label: 'sorting.time.asc', - value: { - key: 'logtime', - type: 'asc' - } - }, - { - label: 'sorting.time.desc', - value: { - key: 'logtime', - type: 'desc' - } - } - ], - defaultValue: '', - defaultLabel: '' - }, - pageSize: { - label: 'pagination.title', - options: paginationOptions.map((option: string): ListItem => { - return { - label: option, - value: option - } - }), - defaultValue: '10', - defaultLabel: '10' - }, - page: { - defaultValue: 0 - }, - query: {} -}; - -export const filtersFormItemsMap: {[key: string]: string[]} = { - serviceLogs: ['clusters', 'timeRange', 'components', 'levels', 'hosts', 'sorting', 'pageSize', 'page', 'query'], - auditLogs: ['clusters', 'timeRange', 'sorting', 'pageSize', 'page', 'query'] // TODO add all the required fields -}; - -export const getFiltersForm = (listType: string): FormGroup => { - const itemsList = filtersFormItemsMap[listType], - keys = Object.keys(filters).filter((key: string): boolean => itemsList.indexOf(key) > -1), - items = keys.reduce((currentObject: any, key: string): any => { - let formControl = new FormControl(), - item = { - [key]: formControl - }; - formControl.setValue(filters[key].defaultValue); - return Object.assign(currentObject, item); - }, {}); - return new FormGroup(items); -}; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-state.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-state.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-state.ts index 2c5c083..afed497 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-state.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/app-state.ts @@ -16,9 +16,7 @@ * limitations under the License. */ -import {FormGroup} from '@angular/forms'; import {ActiveServiceLogEntry} from '@app/classes/active-service-log-entry'; -import {Tab, initialTabs} from '@app/classes/models/tab'; export interface AppState { isAuthorized: boolean; @@ -28,7 +26,7 @@ export interface AppState { isServiceLogsFileView: boolean; isServiceLogContextView: boolean; activeLog: ActiveServiceLogEntry | null; - activeFiltersForm: FormGroup; + activeFilters: object; } export const initialState: AppState = { @@ -39,5 +37,5 @@ export const initialState: AppState = { isServiceLogsFileView: false, isServiceLogContextView: false, activeLog: null, - activeFiltersForm: initialTabs.find((tab: Tab): boolean => tab.isActive).appState.activeFiltersForm + activeFilters: null }; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts index fbe0e46..380f14f 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts @@ -35,7 +35,7 @@ export interface AuditLog extends Log { repoType: number; repo: string; proxyUsers?: string[]; - evtTime: string; + evtTime: number; enforcer: string; reqContext?: string; cliType?: string; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node-item.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node-item.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node-item.ts new file mode 100644 index 0000000..ef5f772 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node-item.ts @@ -0,0 +1,30 @@ +/** + * 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 {CommonEntry} from '@app/classes/models/common-entry'; + +export interface NodeItem { + name: string; + type?: string; + value: string; + isParent: boolean; + isRoot: boolean; + childs?: NodeItem[]; + logLevelCount?: CommonEntry[]; + vNodeList?: CommonEntry[]; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node.ts deleted file mode 100644 index a14e51a..0000000 --- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/node.ts +++ /dev/null @@ -1,30 +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 {CommonEntry} from '@app/classes/models/common-entry'; - -export interface Node { - name: string; - type?: string; - value: string; - isParent: boolean; - isRoot: boolean; - childs?: Node[]; - logLevelCount?: CommonEntry[]; - vNodeList?: CommonEntry[]; -} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts index d912b35..f996d92 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/store.ts @@ -24,7 +24,7 @@ import {AuditLog} from '@app/classes/models/audit-log'; import {ServiceLog} from '@app/classes/models/service-log'; import {BarGraph} from '@app/classes/models/bar-graph'; import {Graph} from '@app/classes/models/graph'; -import {Node} from '@app/classes/models/node'; +import {NodeItem} from '@app/classes/models/node-item'; import {UserConfig} from '@app/classes/models/user-config'; import {Filter} from '@app/classes/models/filter'; import {AuditLogField} from '@app/classes/models/audit-log-field'; @@ -50,11 +50,11 @@ export interface AppStore { serviceLogsHistogramData: BarGraph[]; serviceLogsTruncated: ServiceLog[]; graphs: Graph[]; - hosts: Node[]; + hosts: NodeItem[]; userConfigs: UserConfig[]; filters: Filter[]; clusters: string[]; - components: Node[]; + components: NodeItem[]; serviceLogsFields: ServiceLogField[]; auditLogsFields: AuditLogField[]; tabs: Tab[]; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/tab.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/tab.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/tab.ts index bb8028a..05ea59d 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/tab.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/tab.ts @@ -16,15 +16,13 @@ * limitations under the License. */ -import {getFiltersForm} from '@app/classes/filtering'; - export interface Tab { id: string; type: string; - isActive: boolean; + isActive?: boolean; isCloseable?: boolean; label: string; - appState: any; + appState?: object; } export const initialTabs: Tab[] = [ @@ -35,8 +33,7 @@ export const initialTabs: Tab[] = [ label: 'common.serviceLogs', appState: { activeLogsType: 'serviceLogs', - isServiceLogsFileView: false, - activeFiltersForm: getFiltersForm('serviceLogs') + isServiceLogsFileView: false } }, { @@ -46,8 +43,7 @@ export const initialTabs: Tab[] = [ label: 'common.auditLogs', appState: { activeLogsType: 'auditLogs', - isServiceLogsFileView: false, - activeFiltersForm: getFiltersForm('auditLogs') + isServiceLogsFileView: false } } ]; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html new file mode 100644 index 0000000..ab6326a --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html @@ -0,0 +1,20 @@ +<!-- + 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. +--> +<menu-button *ngFor="let item of items" label="{{item.label | translate}}" [action]="item.action" + [iconClass]="item.iconClass" [labelClass]="item.labelClass" [subItems]="item.subItems" + [hideCaret]="item.hideCaret" [badge]="item.badge" [isRightAlign]="item.isRightAlign"> +</menu-button> http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less new file mode 100644 index 0000000..880a97b --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less @@ -0,0 +1,27 @@ +/** + * 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'; + +:host { + display: block; + margin-left: auto; + menu-button { + margin: 0 1em; + color: @table-border-color; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts new file mode 100644 index 0000000..081304e --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts @@ -0,0 +1,47 @@ +/** + * 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 {TranslationModules} from '@app/test-config.spec'; + +import {ActionMenuComponent} from './action-menu.component'; + +describe('ActionMenuComponent', () => { + let component: ActionMenuComponent; + let fixture: ComponentFixture<ActionMenuComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: TranslationModules, + declarations: [ActionMenuComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ActionMenuComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create component', () => { + expect(component).toBeTruthy(); + }); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts new file mode 100644 index 0000000..58e0025 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts @@ -0,0 +1,105 @@ +/** + * 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} from '@angular/core'; + +@Component({ + selector: 'action-menu', + templateUrl: './action-menu.component.html', + styleUrls: ['./action-menu.component.less'] +}) +export class ActionMenuComponent { + + //TODO implement loading of real data into subItems + readonly items = [ + { + iconClass: 'fa fa-arrow-left', + label: 'topMenu.undo', + labelClass: 'unstyled-link', + action: 'undo', + subItems: [ + { + label: 'Apply \'Last week\' filter' + }, + { + label: 'Clear all filters' + }, + { + label: 'Apply \'HDFS\' filter' + }, + { + label: 'Apply \'Errors\' filter' + } + ] + }, + { + iconClass: 'fa fa-arrow-right', + label: 'topMenu.redo', + labelClass: 'unstyled-link', + action: 'redo', + subItems: [ + { + label: 'Apply \'Warnings\' filter' + }, + { + label: 'Switch to graph mode' + }, + { + label: 'Apply \'Custom Date\' filter' + } + ] + }, + { + iconClass: 'fa fa-refresh', + label: 'topMenu.refresh', + labelClass: 'unstyled-link', + action: 'refresh' + }, + { + iconClass: 'fa fa-history', + label: 'topMenu.history', + labelClass: 'unstyled-link', + action: 'openHistory', + isRightAlign: true, + subItems: [ + { + label: 'Apply \'Custom Date\' filter' + }, + { + label: 'Switch to graph mode' + }, + { + label: 'Apply \'Warnings\' filter' + }, + { + label: 'Apply \'Last week\' filter' + }, + { + label: 'Clear all filters' + }, + { + label: 'Apply \'HDFS\' filter' + }, + { + label: 'Apply \'Errors\' filter' + } + ] + } + ]; + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.html index a0444c9..833f43f 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.html +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.html @@ -18,8 +18,8 @@ <header> <nav class="navbar navbar-fixed-top"> <div class="container-fluid"> - <h1 [ngClass]="{'full-flex-width': !isAuthorized, 'navbar-left': true}">{{'common.title' | translate}}</h1> - <top-menu *ngIf="isAuthorized" class="navbar-right"></top-menu> + <h1 [ngClass]="{'full-flex-width': !isAuthorized, 'pull-left': true}">{{'common.title' | translate}}</h1> + <top-menu *ngIf="isAuthorized"></top-menu> </div> </nav> </header> http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.less index 8731582..f0fecfc 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.less +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.less @@ -31,11 +31,10 @@ color: #fff; .container-fluid { - .default-flex; + .stretch-flex; } h1 { - flex-basis: 70%; margin-bottom: @h1-vertical-margin; text-transform: uppercase; @@ -45,7 +44,7 @@ } /deep/ top-menu { - flex-basis: 30%; + margin-left: auto; } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.spec.ts index 490e058..bae05ce 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.spec.ts @@ -53,9 +53,9 @@ describe('AppComponent', () => { }).compileComponents(); })); - it('should create the app', async(() => { + it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); - })); + }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.ts index 4de47ea..038dd2a 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/app.component.ts @@ -30,12 +30,12 @@ import {HttpClientService} from '@app/services/http-client.service'; export class AppComponent { constructor(private httpClient: HttpClientService, private translate: TranslateService, private appState: AppStateService) { - appState.getParameter('isAuthorized').subscribe(value => this.isAuthorized = value); + appState.getParameter('isAuthorized').subscribe((value: boolean) => this.isAuthorized = value); appState.setParameter('isInitialLoading', true); - this.httpClient.get('status').subscribe(() => this.appState.setParameters({ + httpClient.get('status').subscribe(() => appState.setParameters({ isAuthorized: true, isInitialLoading: false - }), () => this.appState.setParameter('isInitialLoading', false)); + }), () => appState.setParameter('isInitialLoading', false)); translate.setDefaultLang('en'); translate.use('en'); } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html new file mode 100644 index 0000000..d6e9091 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html @@ -0,0 +1,54 @@ +<!-- + 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. +--> + +<dropdown-button class="pull-right" label="logs.columns" [options]="columns" [isRightAlign]="true" + [isMultipleChoice]="true" action="updateSelectedColumns" + [additionalArgs]="logsTypeMapObject.fieldsModel"></dropdown-button> +<form *ngIf="logs && logs.length" [formGroup]="filtersForm" class="row pull-right"> + <filter-dropdown class="col-md-12" [label]="filters.auditLogsSorting.label" formControlName="auditLogsSorting" + [options]="filters.auditLogsSorting.options" [isRightAlign]="true"></filter-dropdown></form> +<div class="panel panel-default"> + <div class="panel-body"> + <table class="table"> + <thead> + <tr> + <th *ngIf="isColumnDisplayed('evtTime')">{{getColumnByName('evtTime').label | translate}}</th> + <ng-container *ngFor="let column of displayedColumns"> + <th *ngIf="customProcessedColumns.indexOf(column.value) === -1">{{column.label | translate}}</th> + </ng-container> + </tr> + </thead> + <tbody> + <tr *ngFor="let log of logs"> + <td *ngIf="isColumnDisplayed('evtTime')">{{log.evtTime | amTz: timeZone | amDateFormat: timeFormat}}</td> + <ng-container *ngFor="let column of displayedColumns"> + <td *ngIf="customProcessedColumns.indexOf(column.value) === -1">{{log[column.value]}}</td> + </ng-container> + </tr> + </tbody> + <tfoot> + <tr> + <td attr.colspan="{{displayedColumns.length + 1}}"> + <pagination class="col-md-12" *ngIf="logs && logs.length" [totalCount]="totalCount" + [filtersForm]="filtersForm" [filterInstance]="filters.pageSize" + [currentCount]="logs.length"></pagination> + </td> + </tr> + </tfoot> + </table> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less new file mode 100644 index 0000000..d9b0a10 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less @@ -0,0 +1,21 @@ +/** + * 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. + */ + +th { + text-transform: uppercase; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts new file mode 100644 index 0000000..b6206db --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts @@ -0,0 +1,157 @@ +/** + * 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 {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {StoreModule} from '@ngrx/store'; +import {MomentModule} from 'angular2-moment'; +import {MomentTimezoneModule} from 'angular-moment-timezone'; +import {TranslationModules} from '@app/test-config.spec'; +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 {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service'; +import {AppStateService, appState} from '@app/services/storage/app-state.service'; +import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service'; +import {TabsService, tabs} from '@app/services/storage/tabs.service'; +import {ClustersService, clusters} from '@app/services/storage/clusters.service'; +import {ComponentsService, components} from '@app/services/storage/components.service'; +import {HostsService, hosts} from '@app/services/storage/hosts.service'; +import {LogsContainerService} from '@app/services/logs-container.service'; +import {UtilsService} from '@app/services/utils.service'; +import {HttpClientService} from '@app/services/http-client.service'; +import {PaginationComponent} from '@app/components/pagination/pagination.component'; +import {DropdownListComponent} from '@app/components/dropdown-list/dropdown-list.component'; + +import {AuditLogsTableComponent} from './audit-logs-table.component'; + +describe('AuditLogsTableComponent', () => { + let component: AuditLogsTableComponent; + let fixture: ComponentFixture<AuditLogsTableComponent>; + const httpClient = { + get: () => { + return { + subscribe: () => { + } + }; + } + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AuditLogsTableComponent, + PaginationComponent, + DropdownListComponent + ], + imports: [ + FormsModule, + ReactiveFormsModule, + MomentModule, + MomentTimezoneModule, + ...TranslationModules, + StoreModule.provideStore({ + auditLogs, + serviceLogs, + auditLogsFields, + serviceLogsFields, + serviceLogsHistogramData, + serviceLogsTruncated, + appState, + appSettings, + tabs, + clusters, + components, + hosts + }) + ], + providers: [ + LogsContainerService, + UtilsService, + { + provide: HttpClientService, + useValue: httpClient + }, + AuditLogsService, + ServiceLogsService, + AuditLogsFieldsService, + ServiceLogsFieldsService, + ServiceLogsHistogramDataService, + ServiceLogsTruncatedService, + AppStateService, + AppSettingsService, + TabsService, + ClustersService, + ComponentsService, + HostsService + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AuditLogsTableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create component', () => { + expect(component).toBeTruthy(); + }); + + describe('#getColumnByName()', () => { + const cases = [ + { + name: 'v1', + result: { + label: 'l1', + value: 'v1' + }, + title: 'item is present' + }, + { + name: 'l1', + result: undefined, + title: 'item is absent' + } + ]; + + beforeEach(() => { + component.columns = [ + { + label: 'l0', + value: 'v0' + }, + { + label: 'l1', + value: 'v1' + } + ]; + }); + + cases.forEach(test => { + it(test.title, () => { + expect(component.getColumnByName(test.name)).toEqual(test.result); + }); + }); + }); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts new file mode 100644 index 0000000..0e578ab --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts @@ -0,0 +1,55 @@ +/** + * 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} from '@angular/core'; +import {ListItem} from '@app/classes/list-item'; +import {LogsTableComponent} from '@app/classes/components/logs-table-component'; +import {LogsContainerService} from '@app/services/logs-container.service'; + +@Component({ + selector: 'audit-logs-table', + templateUrl: './audit-logs-table.component.html', + styleUrls: ['./audit-logs-table.component.less'] +}) +export class AuditLogsTableComponent extends LogsTableComponent { + + constructor(private logsContainer: LogsContainerService) { + super(); + } + + readonly customProcessedColumns: string[] = ['evtTime']; + + readonly timeFormat: string = 'YYYY-MM-DD HH:mm:ss,SSS'; + + get logsTypeMapObject(): object { + return this.logsContainer.logsTypeMap.auditLogs; + } + + get filters(): any { + return this.logsContainer.filters; + } + + get timeZone(): string { + return this.logsContainer.timeZone; + } + + getColumnByName(name: string): ListItem | undefined { + return this.columns.find((column: ListItem): boolean => column.value === name); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts index e6c0bfe..dfd9711 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts @@ -18,6 +18,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {StoreModule} from '@ngrx/store'; +import * as moment from 'moment-timezone'; import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service'; import {DatePickerComponent} from './date-picker.component'; @@ -42,6 +43,7 @@ describe('DatePickerComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(DatePickerComponent); component = fixture.componentInstance; + component.time = moment(); fixture.detectChanges(); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts index efb5e34..e33d71e 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts @@ -16,8 +16,11 @@ * limitations under the License. */ -import {Component, OnInit, OnDestroy, Output, EventEmitter, ViewChild, ElementRef} from '@angular/core'; +import { + Component, OnInit, OnChanges, OnDestroy, SimpleChanges, Input, Output, EventEmitter, ViewChild, ElementRef +} from '@angular/core'; import * as $ from 'jquery'; +import {Moment} from 'moment-timezone'; import '@vendor/js/bootstrap-datetimepicker.min'; import {AppSettingsService} from '@app/services/storage/app-settings.service'; @@ -25,10 +28,10 @@ import {AppSettingsService} from '@app/services/storage/app-settings.service'; selector: 'date-picker', templateUrl: './date-picker.component.html' }) -export class DatePickerComponent implements OnInit, OnDestroy { +export class DatePickerComponent implements OnInit, OnChanges, OnDestroy { constructor(private appSettings: AppSettingsService) { - appSettings.getParameter('timeZone').subscribe(value => { + appSettings.getParameter('timeZone').subscribe((value: string): void => { this.destroyDatePicker(); this.timeZone = value; if (this.datePickerElement) { @@ -37,14 +40,27 @@ export class DatePickerComponent implements OnInit, OnDestroy { }); } - ngOnInit() { + ngOnInit(): void { this.createDatePicker(); } - ngOnDestroy() { + ngOnChanges(changes: SimpleChanges): void { + if (changes.hasOwnProperty('time') && this.datePickerElement) { + this.setTime(changes.time.currentValue); + } + } + + ngOnDestroy(): void { this.destroyDatePicker(); } + /** + * Value of time input field passed from parent component + * @type {Moment} + */ + @Input() + time: Moment; + @Output() timeChange: EventEmitter<number> = new EventEmitter(); @@ -60,6 +76,7 @@ export class DatePickerComponent implements OnInit, OnDestroy { this.datePickerElement.datetimepicker({ timeZone: this.timeZone }); + this.setTime(this.time); this.datePickerElement.on('dp.change', event => this.timeChange.emit(event.date)); } @@ -70,4 +87,12 @@ export class DatePickerComponent implements OnInit, OnDestroy { } } + /** + * Set value to time input field + * @param {Moment} time + */ + private setTime(time: Moment): void { + this.datePickerElement.data('DateTimePicker').date(time); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.html index 798a609..b5f1e56 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.html +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.html @@ -22,10 +22,10 @@ <span *ngIf="iconClass" [ngClass]="iconClass"></span> <span *ngIf="label">{{label | translate}}</span> </span> - <span *ngIf="showSelectedValue && !isMultipleChoice">{{selectedLabel | translate}}</span> + <span *ngIf="showSelectedValue && !isMultipleChoice && selection.length">{{selection[0].label | translate}}</span> <span *ngIf="!hideCaret" class="caret"></span> </button> <ul data-component="dropdown-list" [ngClass]="{'dropdown-menu': true, 'dropdown-menu-right': isRightAlign}" - [items]="options" [isMultipleChoice]="isMultipleChoice" (selectedItemChange)="updateValue($event)" + [items]="options" [isMultipleChoice]="isMultipleChoice" (selectedItemChange)="updateSelection($event)" [actionArguments]="additionalArgs"></ul> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.spec.ts index f11ca09..fc42e3c 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.spec.ts @@ -32,11 +32,11 @@ import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service'; import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service'; import {TabsService, tabs} from '@app/services/storage/tabs.service'; -import {FilteringService} from '@app/services/filtering.service'; import {UtilsService} from '@app/services/utils.service'; import {ComponentActionsService} from '@app/services/component-actions.service'; import {HttpClientService} from '@app/services/http-client.service'; import {LogsContainerService} from '@app/services/logs-container.service'; +import {AuthService} from '@app/services/auth.service'; import {DropdownButtonComponent} from './dropdown-button.component'; @@ -85,14 +85,14 @@ describe('DropdownButtonComponent', () => { ServiceLogsHistogramDataService, ServiceLogsTruncatedService, TabsService, - FilteringService, UtilsService, ComponentActionsService, { provide: HttpClientService, useValue: httpClient }, - LogsContainerService + LogsContainerService, + AuthService ], schemas: [NO_ERRORS_SCHEMA] }) http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.ts index 0bf4422..148e1b4 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-button/dropdown-button.component.ts @@ -16,7 +16,7 @@ * limitations under the License. */ -import {Component, OnInit, Input} from '@angular/core'; +import {Component, Input} from '@angular/core'; import {ListItem} from '@app/classes/list-item'; import {ComponentActionsService} from '@app/services/component-actions.service'; import {UtilsService} from '@app/services/utils.service'; @@ -26,14 +26,10 @@ import {UtilsService} from '@app/services/utils.service'; templateUrl: './dropdown-button.component.html', styleUrls: ['./dropdown-button.component.less'] }) -export class DropdownButtonComponent implements OnInit { +export class DropdownButtonComponent { constructor(protected actions: ComponentActionsService, protected utils: UtilsService) { } - - ngOnInit() { - this.selectedLabel = this.defaultLabel; - } @Input() label?: string; @@ -48,13 +44,7 @@ export class DropdownButtonComponent implements OnInit { showSelectedValue: boolean = true; @Input() - options?: ListItem[]; - - @Input() - defaultValue?: string; - - @Input() - defaultLabel?: string; + options: ListItem[] = []; @Input() action?: string; @@ -71,36 +61,33 @@ export class DropdownButtonComponent implements OnInit { @Input() isDropup: boolean = false; - protected selectedValue?: any; - - selectedLabel: string; + protected selectedItems?: ListItem[] = []; - get value(): any { - return this.selectedValue; + get selection(): ListItem[] { + return this.selectedItems; } - set value(value: any) { - this.selectedValue = value; + set selection(items: ListItem[]) { + this.selectedItems = items; } - updateValue(eventOptions: ListItem): void { - const value = eventOptions && eventOptions.value, - action = this.action && this.actions[this.action]; + updateSelection(item: ListItem): void { + const 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; + this.options.find((option: ListItem): boolean => { + return this.utils.isEqual(option.value, item.value); + }).isChecked = item.isChecked; + const checkedItems = this.options.filter((option: ListItem): boolean => option.isChecked); + this.selection = checkedItems; if (action) { - action(this.options.filter(item => item.isChecked).map(item => item.value), ...this.additionalArgs); + action(checkedItems.map((option: ListItem): any => option.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); - } + } else if (!this.utils.isEqual(this.selection[0], item)) { + this.selection = [item]; + if (action) { + action(item.value, ...this.additionalArgs); } } } - + } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.html ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.html index 5de78ad..df564e5 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.html +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.html @@ -17,7 +17,7 @@ <li *ngFor="let item of items"> <label class="list-item-label" *ngIf="isMultipleChoice"> - <input type="checkbox" [attr.id]="item.id || item.value" [attr.checked]="item.isChecked ? 'checked' : null" + <input type="checkbox" [attr.id]="item.id || item.value" [(ngModel)]="item.isChecked" (change)="changeSelectedItem({value: item.value, isChecked: $event.currentTarget.checked})"> <label [attr.for]="item.id || item.value" class="label-container"> <span *ngIf="item.iconClass" [ngClass]="item.iconClass"></span> http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.spec.ts index 5455e67..63824cb 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/dropdown-list/dropdown-list.component.spec.ts @@ -17,6 +17,7 @@ */ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {FormsModule} from '@angular/forms'; import {StoreModule} from '@ngrx/store'; import {TranslationModules} from '@app/test-config.spec'; import {HostsService, hosts} from '@app/services/storage/hosts.service'; @@ -34,8 +35,8 @@ import {TabsService, tabs} from '@app/services/storage/tabs.service'; import {ComponentGeneratorService} from '@app/services/component-generator.service'; import {LogsContainerService} from '@app/services/logs-container.service'; import {HttpClientService} from '@app/services/http-client.service'; -import {FilteringService} from '@app/services/filtering.service'; import {ComponentActionsService} from '@app/services/component-actions.service'; +import {AuthService} from '@app/services/auth.service'; import {DropdownListComponent} from './dropdown-list.component'; @@ -69,7 +70,8 @@ describe('DropdownListComponent', () => { components, serviceLogsTruncated, tabs - }) + }), + FormsModule ], providers: [ ComponentGeneratorService, @@ -78,7 +80,6 @@ describe('DropdownListComponent', () => { provide: HttpClientService, useValue: httpClient }, - FilteringService, ComponentActionsService, HostsService, AuditLogsService, @@ -91,7 +92,8 @@ describe('DropdownListComponent', () => { ClustersService, ComponentsService, ServiceLogsTruncatedService, - TabsService + TabsService, + AuthService ] }) .compileComponents(); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.spec.ts index 3e40455..6a9aca5 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.spec.ts @@ -33,10 +33,10 @@ import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/se import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service'; import {TabsService, tabs} from '@app/services/storage/tabs.service'; import {ComponentActionsService} from '@app/services/component-actions.service'; -import {FilteringService} from '@app/services/filtering.service'; import {UtilsService} from '@app/services/utils.service'; import {HttpClientService} from '@app/services/http-client.service'; import {LogsContainerService} from '@app/services/logs-container.service'; +import {AuthService} from '@app/services/auth.service'; import {FilterButtonComponent} from './filter-button.component'; @@ -86,13 +86,13 @@ describe('FilterButtonComponent', () => { ServiceLogsTruncatedService, TabsService, ComponentActionsService, - FilteringService, UtilsService, { provide: HttpClientService, useValue: httpClient }, - LogsContainerService + LogsContainerService, + AuthService ], schemas: [NO_ERRORS_SCHEMA] }) http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-button/filter-button.component.ts ---------------------------------------------------------------------- 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 2c8ecd7..2dcecd1 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 @@ -41,34 +41,35 @@ export class FilterButtonComponent extends MenuButtonComponent implements Contro super(actions); } - @Input() - defaultValue?: string; - - private selectedValue: any; + private selectedItems: ListItem[] = []; private onChange: (fn: any) => void; - get value(): any { - return this.selectedValue; + get selection(): ListItem[] { + return this.selectedItems; } - set value(newValue: any) { - this.selectedValue = newValue; - this.onChange(newValue); + set selection(items: ListItem[]) { + this.selectedItems = items; + if (this.onChange) { + this.onChange(items); + } } - updateValue(options: ListItem): void { - const value = options && options.value; + updateSelection(item: ListItem): void { if (this.isMultipleChoice) { - this.value = this.utils.updateMultiSelectValue(this.value, value, options.isChecked); - } else { - if (this.utils.valueHasChanged(this.selectedValue, value)) { - this.value = value; - } + this.subItems.find((option: ListItem): boolean => { + return this.utils.isEqual(option.value, item.value); + }).isChecked = item.isChecked; + const checkedItems = this.subItems.filter((option: ListItem): boolean => option.isChecked); + this.selection = checkedItems; + } else if (!this.utils.isEqual(this.selection[0], item)) { + this.selection = [item]; } } - writeValue() { + writeValue(items: ListItem[]) { + this.selection = items; } registerOnChange(callback: any): void { http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.spec.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.spec.ts index c294e8e..8293ba0 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.spec.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.spec.ts @@ -28,11 +28,14 @@ import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service'; import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service'; import {TabsService, tabs} from '@app/services/storage/tabs.service'; -import {FilteringService} from '@app/services/filtering.service'; +import {ClustersService, clusters} from '@app/services/storage/clusters.service'; +import {ComponentsService, components} from '@app/services/storage/components.service'; +import {HostsService, hosts} from '@app/services/storage/hosts.service'; import {UtilsService} from '@app/services/utils.service'; import {ComponentActionsService} from '@app/services/component-actions.service'; import {LogsContainerService} from '@app/services/logs-container.service'; import {HttpClientService} from '@app/services/http-client.service'; +import {AuthService} from '@app/services/auth.service'; import {FilterDropdownComponent} from './filter-dropdown.component'; @@ -77,7 +80,10 @@ describe('FilterDropdownComponent', () => { serviceLogsFields, serviceLogsHistogramData, serviceLogsTruncated, - tabs + tabs, + clusters, + components, + hosts }), ...TranslationModules ], @@ -91,8 +97,11 @@ describe('FilterDropdownComponent', () => { ServiceLogsHistogramDataService, ServiceLogsTruncatedService, TabsService, + ClustersService, + ComponentsService, + HostsService, { - provide: FilteringService, + provide: LogsContainerService, useValue: filtering }, UtilsService, @@ -101,7 +110,8 @@ describe('FilterDropdownComponent', () => { { provide: HttpClientService, useValue: httpClient - } + }, + AuthService ], schemas: [NO_ERRORS_SCHEMA] }) http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.ts ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.ts index 9e5a6f1..d677d81 100644 --- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.ts +++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filter-dropdown/filter-dropdown.component.ts @@ -20,6 +20,7 @@ import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import {ComponentActionsService} from '@app/services/component-actions.service'; import {UtilsService} from '@app/services/utils.service'; import {DropdownButtonComponent} from '@app/components/dropdown-button/dropdown-button.component'; +import {ListItem} from '@app/classes/list-item'; @Component({ selector: 'filter-dropdown', @@ -41,16 +42,25 @@ export class FilterDropdownComponent extends DropdownButtonComponent implements private onChange: (fn: any) => void; - get value(): any { - return this.selectedValue; + get selection(): ListItem[] { + return this.selectedItems; } - set value(newValue: any) { - this.selectedValue = newValue; - this.onChange(newValue); + set selection(items: ListItem[]) { + this.selectedItems = items; + if (this.isMultipleChoice) { + this.options.forEach((option: ListItem): void => { + const selectionItem = items.find((item: ListItem): boolean => this.utils.isEqual(item.value, option.value)); + option.isChecked = Boolean(selectionItem); + }); + } + if (this.onChange) { + this.onChange(items); + } } - writeValue() { + writeValue(items: ListItem[]) { + this.selection = items; } registerOnChange(callback: any): void { http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/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 fa739a4..2d327a6 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 @@ -17,13 +17,13 @@ <form [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" [isMultipleChoice]="true" + <filter-dropdown *ngIf="isFilterConditionDisplayed('clusters')" [label]="filters.clusters.label" + formControlName="clusters" [options]="filters.clusters.options" [isMultipleChoice]="true" class="filter-input"></filter-dropdown> <search-box formControlName="query" [items]="searchBoxItemsTranslated" class="filter-input" [parameterNameChangeSubject]="queryParameterNameChange" [parameterAddSubject]="queryParameterAdd"></search-box> - <time-range-picker formControlName="timeRange" [defaultLabel]="filters.timeRange.defaultLabel" + <time-range-picker *ngIf="isFilterConditionDisplayed('timeRange')" formControlName="timeRange" class="filter-input"></time-range-picker> <timezone-picker class="filter-input"></timezone-picker> <!--button class="btn btn-success" type="button"> http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/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 0bb0204..1f7e8db 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 @@ -18,6 +18,7 @@ import {NO_ERRORS_SCHEMA} from '@angular/core'; import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {FormGroup, FormControl} from '@angular/forms'; import {TranslationModules} from '@app/test-config.spec'; import {StoreModule} from '@ngrx/store'; import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service'; @@ -32,7 +33,6 @@ import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/se import {AppStateService, appState} from '@app/services/storage/app-state.service'; import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service'; import {TabsService, tabs} from '@app/services/storage/tabs.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'; @@ -88,7 +88,6 @@ describe('FiltersPanelComponent', () => { AppStateService, ServiceLogsTruncatedService, TabsService, - FilteringService, LogsContainerService, { provide: HttpClientService, @@ -104,6 +103,9 @@ describe('FiltersPanelComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(FiltersPanelComponent); component = fixture.componentInstance; + component.filtersForm = new FormGroup({ + control: new FormControl() + }); fixture.detectChanges(); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/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 9601a0e..b41f7cd 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 @@ -21,10 +21,8 @@ import {FormGroup} from '@angular/forms'; import {Subject} from 'rxjs/Subject'; import {TranslateService} from '@ngx-translate/core'; import {ListItem} from '@app/classes/list-item'; -import {filtersFormItemsMap} from '@app/classes/filtering'; import {CommonEntry} from '@app/classes/models/common-entry'; import {LogField} from '@app/classes/models/log-field'; -import {FilteringService} from '@app/services/filtering.service'; import {LogsContainerService} from '@app/services/logs-container.service'; import {AppStateService} from '@app/services/storage/app-state.service'; @@ -35,7 +33,10 @@ import {AppStateService} from '@app/services/storage/app-state.service'; }) export class FiltersPanelComponent { - constructor(private translate: TranslateService, private filtering: FilteringService, private logsContainer: LogsContainerService, private appState: AppStateService) { + constructor( + private translate: TranslateService, private logsContainer: LogsContainerService, + private appState: AppStateService + ) { appState.getParameter('activeLogsType').subscribe(value => { this.logsType = value; logsContainer.logsTypeMap[value].fieldsModel.getAll().subscribe((fields: LogField[]): void => { @@ -80,23 +81,24 @@ export class FiltersPanelComponent { searchBoxItemsTranslated: CommonEntry[] = []; get filters(): any { - return this.filtering.filters; + return this.logsContainer.filters; } get queryParameterNameChange(): Subject<any> { - return this.filtering.queryParameterNameChange; + return this.logsContainer.queryParameterNameChange; } get queryParameterAdd(): Subject<any> { - return this.filtering.queryParameterAdd; + return this.logsContainer.queryParameterAdd; } get captureSeconds(): number { - return this.filtering.captureSeconds; + return this.logsContainer.captureSeconds; } isFilterConditionDisplayed(key: string): boolean { - return filtersFormItemsMap[this.logsType].indexOf(key) > -1; + return this.logsContainer.logsTypeMap[this.logsType].listFilters.indexOf(key) > -1 + && Boolean(this.filtersForm.controls[key]); } }
