You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ol...@apache.org on 2018/11/29 18:32:09 UTC
[ambari-logsearch] branch master updated: [AMBARI-24880] [Log
Search UI] Create new layout for the Audit log list. (#48)
This is an automated email from the ASF dual-hosted git repository.
oleewere pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ambari-logsearch.git
The following commit(s) were added to refs/heads/master by this push:
new d936951 [AMBARI-24880] [Log Search UI] Create new layout for the Audit log list. (#48)
d936951 is described below
commit d936951666c9cd4e8dc1ae8f64943162f181681d
Author: Istvan Tobias <to...@gmail.com>
AuthorDate: Thu Nov 29 19:32:04 2018 +0100
[AMBARI-24880] [Log Search UI] Create new layout for the Audit log list. (#48)
* [AMBARI-24880] [Log Search UI] Create new layout for the Audit log list.
* [AMBARI-24880] [Log Search UI] Create new layout for the Audit log list.
* [AMBARI-24880] [Log Search UI] Create new layout for the Audit log list. - Feedback changes
* [AMBARI-24880] [Log Search UI] Create new layout for the Audit log list. - Accidentally commited karma Chrome launcher settings
* [AMBARI-24880] [Log Search UI] Create new layout for the Audit log list. - fixes for PR feedbacks
---
ambari-logsearch-web/package.json | 3 +-
ambari-logsearch-web/src/app/app.module.ts | 184 +++++++++++----------
.../classes/components/graph/graph.component.ts | 54 +++---
.../logs-table/logs-table-component.spec.ts | 10 +-
.../components/logs-table/logs-table-component.ts | 44 +++--
.../src/app/classes/models/audit-log.ts | 2 +
.../src/app/classes/models/store.ts | 6 +-
ambari-logsearch-web/src/app/classes/object.ts | 6 +-
.../audit-logs-entries.component.html | 2 +-
.../audit-logs-entries.component.less} | 28 ++--
.../audit-logs-entries.component.ts | 79 ++++++---
.../audit-logs-table.component.html | 84 ++++++----
.../audit-logs-table.component.less | 84 +++++++++-
.../audit-logs-table.component.spec.ts | 7 +
.../audit-logs-table/audit-logs-table.component.ts | 63 ++++++-
.../collapsible-panel.component.less | 3 +-
.../collapsible-panel.component.ts | 10 +-
.../filters-panel/filters-panel.component.html | 11 ++
.../graph-legend/graph-legend.component.html | 3 +-
.../graph-legend/graph-legend.component.ts | 4 +-
.../horizontal-histogram.component.html | 4 +-
.../horizontal-histogram.component.ts | 51 +++---
.../logs-container/logs-container.component.html | 4 +-
.../logs-container/logs-container.component.ts | 7 +-
.../components/search-box/search-box.component.ts | 27 ++-
.../service-logs-table.component.ts | 6 +-
.../time-line-graph/time-line-graph.component.ts | 23 +--
.../modules/app-load/services/app-load.service.ts | 33 +++-
.../dropdown-button/dropdown-button.component.html | 4 +-
.../dropdown-button/dropdown-button.component.ts | 6 +
.../dropdown-list/dropdown-list.component.html | 2 +-
.../dropdown-list/dropdown-list.component.ts | 11 ++
.../src/app/modules/shared/dashrows.less | 92 +++++++++++
.../src/app/modules/shared/main.less | 1 +
.../src/app/modules/shared/mixins.less | 29 ++++
.../src/app/modules/shared/variables.less | 22 ++-
.../pipes/audit-log-field-label.pipe.ts} | 28 ++--
.../src/{styles.less => app/pipes/repo-label.ts} | 28 ++--
.../src/app/services/http-client.service.ts | 3 +
.../src/app/services/logs-container.service.ts | 77 ++++-----
.../app/services/logs-filtering-utils.service.ts | 1 +
.../src/app/services/storage/reducers.service.ts | 4 +-
.../app/store/actions/audit-log-repos.actions.ts | 52 ++++++
.../app/store/effects/audit-log-repos.effects.ts | 59 +++++++
.../store/reducers/audit-log-repos.reducers.ts} | 29 ++--
.../selectors/audit-log-repos.selectors.ts} | 39 ++---
.../store/selectors/audit-logs-fields.selectors.ts | 27 ++-
ambari-logsearch-web/src/assets/i18n/en.json | 8 +-
ambari-logsearch-web/src/styles.less | 6 +-
ambari-logsearch-web/yarn.lock | 183 +++++++++++++++++++-
50 files changed, 1132 insertions(+), 421 deletions(-)
diff --git a/ambari-logsearch-web/package.json b/ambari-logsearch-web/package.json
index 2b1e7ef..2840e6d 100644
--- a/ambari-logsearch-web/package.json
+++ b/ambari-logsearch-web/package.json
@@ -39,6 +39,7 @@
"font-awesome": "^4.7.0",
"jquery": "^1.12.4",
"karma-chrome-launcher": "^2.2.0",
+ "less": "^3.8.1",
"moment": "^2.18.1",
"moment-timezone": "^0.5.13",
"ngx-bootstrap": "^2.0.5",
@@ -76,7 +77,7 @@
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-phantomjs-launcher": "^1.0.4",
- "less-loader": "^4.0.5",
+ "less-loader": "^4.1.0",
"postcss-loader": "^1.3.3",
"postcss-url": "^5.1.2",
"protractor": "~5.1.0",
diff --git a/ambari-logsearch-web/src/app/app.module.ts b/ambari-logsearch-web/src/app/app.module.ts
index 9026f67..ac1f0f3 100644
--- a/ambari-logsearch-web/src/app/app.module.ts
+++ b/ambari-logsearch-web/src/app/app.module.ts
@@ -16,107 +16,110 @@
* limitations under the License.
*/
-import {BrowserModule} from '@angular/platform-browser';
-import {NgModule, CUSTOM_ELEMENTS_SCHEMA, APP_INITIALIZER, Injector} from '@angular/core';
-import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule, CUSTOM_ELEMENTS_SCHEMA, APP_INITIALIZER, Injector } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule, Http } from '@angular/http';
-import {TypeaheadModule, TooltipModule} from 'ngx-bootstrap';
-import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
-import {StoreModule} from '@ngrx/store';
-import {StoreDevtoolsModule} from '@ngrx/store-devtools';
-import {MomentModule} from 'angular2-moment';
-import {MomentTimezoneModule} from 'angular-moment-timezone';
-import {NgStringPipesModule} from 'angular-pipes';
-import {SimpleNotificationsModule} from 'angular2-notifications';
+import { TypeaheadModule, TooltipModule } from 'ngx-bootstrap';
+import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
+import { StoreModule } from '@ngrx/store';
+import { StoreDevtoolsModule } from '@ngrx/store-devtools';
+import { MomentModule } from 'angular2-moment';
+import { MomentTimezoneModule } from 'angular-moment-timezone';
+import { NgStringPipesModule } from 'angular-pipes';
+import { SimpleNotificationsModule } from 'angular2-notifications';
import { EffectsModule } from '@ngrx/effects';
-import {SharedModule} from '@modules/shared/shared.module';
-import {AppLoadModule} from '@modules/app-load/app-load.module';
-import {ShipperModule} from '@modules/shipper/shipper.module';
+import { SharedModule } from '@modules/shared/shared.module';
+import { AppLoadModule } from '@modules/app-load/app-load.module';
+import { ShipperModule } from '@modules/shipper/shipper.module';
-import {ServiceInjector} from '@app/classes/service-injector';
+import { ServiceInjector } from '@app/classes/service-injector';
-import {HttpClientService} from '@app/services/http-client.service';
-import {UtilsService} from '@app/services/utils.service';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {ComponentGeneratorService} from '@app/services/component-generator.service';
-import {UserSettingsService} from '@app/services/user-settings.service';
+import { HttpClientService } from '@app/services/http-client.service';
+import { UtilsService } from '@app/services/utils.service';
+import { LogsContainerService } from '@app/services/logs-container.service';
+import { ComponentGeneratorService } from '@app/services/component-generator.service';
+import { UserSettingsService } from '@app/services/user-settings.service';
-import {AppSettingsService} from '@app/services/storage/app-settings.service';
-import {AppStateService} from '@app/services/storage/app-state.service';
-import {AuditLogsService} from '@app/services/storage/audit-logs.service';
-import {AuditLogsGraphDataService} from '@app/services/storage/audit-logs-graph-data.service';
-import {ServiceLogsService} from '@app/services/storage/service-logs.service';
-import {ServiceLogsHistogramDataService} from '@app/services/storage/service-logs-histogram-data.service';
-import {ServiceLogsTruncatedService} from '@app/services/storage/service-logs-truncated.service';
-import {GraphsService} from '@app/services/storage/graphs.service';
-import {HostsService} from '@app/services/storage/hosts.service';
-import {UserConfigsService} from '@app/services/storage/user-configs.service';
-import {ClustersService} from '@app/services/storage/clusters.service';
-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 { AppSettingsService } from '@app/services/storage/app-settings.service';
+import { AppStateService } from '@app/services/storage/app-state.service';
+import { AuditLogsService } from '@app/services/storage/audit-logs.service';
+import { AuditLogsGraphDataService } from '@app/services/storage/audit-logs-graph-data.service';
+import { ServiceLogsService } from '@app/services/storage/service-logs.service';
+import { ServiceLogsHistogramDataService } from '@app/services/storage/service-logs-histogram-data.service';
+import { ServiceLogsTruncatedService } from '@app/services/storage/service-logs-truncated.service';
+import { GraphsService } from '@app/services/storage/graphs.service';
+import { HostsService } from '@app/services/storage/hosts.service';
+import { UserConfigsService } from '@app/services/storage/user-configs.service';
+import { ClustersService } from '@app/services/storage/clusters.service';
+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';
-import {LoginFormComponent} from '@app/components/login-form/login-form.component';
-import {TopMenuComponent} from '@app/components/top-menu/top-menu.component';
-import {MenuButtonComponent} from '@app/components/menu-button/menu-button.component';
-import {MainContainerComponent} from '@app/components/main-container/main-container.component';
-import {FiltersPanelComponent} from '@app/components/filters-panel/filters-panel.component';
-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 {LogMessageComponent} from '@app/components/log-message/log-message.component';
-import {LogLevelComponent} from '@app/components/log-level/log-level.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 {TimeZonePickerComponent} from '@app/components/timezone-picker/timezone-picker.component';
-import {NodeBarComponent} from '@app/components/node-bar/node-bar.component';
-import {SearchBoxComponent} from '@app/components/search-box/search-box.component';
-import {TimeRangePickerComponent} from '@app/components/time-range-picker/time-range-picker.component';
-import {DatePickerComponent} from '@app/components/date-picker/date-picker.component';
-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 {AuditLogsEntriesComponent} from '@app/components/audit-logs-entries/audit-logs-entries.component';
-import {GraphLegendComponent} from '@app/components/graph-legend/graph-legend.component';
-import {HorizontalHistogramComponent} from '@app/components/horizontal-histogram/horizontal-histogram.component';
-import {GraphTooltipComponent} from '@app/components/graph-tooltip/graph-tooltip.component';
-import {GraphLegendItemComponent} from '@app/components/graph-legend-item/graph-legend-item.component';
-import {TimeLineGraphComponent} from '@app/components/time-line-graph/time-line-graph.component';
-import {ContextMenuComponent} from '@app/components/context-menu/context-menu.component';
-import {HistoryItemControlsComponent} from '@app/components/history-item-controls/history-item-controls.component';
-import {LogIndexFilterComponent} from '@app/components/log-index-filter/log-index-filter.component';
+import { AppComponent } from '@app/components/app.component';
+import { LoginFormComponent } from '@app/components/login-form/login-form.component';
+import { TopMenuComponent } from '@app/components/top-menu/top-menu.component';
+import { MenuButtonComponent } from '@app/components/menu-button/menu-button.component';
+import { MainContainerComponent } from '@app/components/main-container/main-container.component';
+import { FiltersPanelComponent } from '@app/components/filters-panel/filters-panel.component';
+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 { LogMessageComponent } from '@app/components/log-message/log-message.component';
+import { LogLevelComponent } from '@app/components/log-level/log-level.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 { TimeZonePickerComponent } from '@app/components/timezone-picker/timezone-picker.component';
+import { NodeBarComponent } from '@app/components/node-bar/node-bar.component';
+import { SearchBoxComponent } from '@app/components/search-box/search-box.component';
+import { TimeRangePickerComponent } from '@app/components/time-range-picker/time-range-picker.component';
+import { DatePickerComponent } from '@app/components/date-picker/date-picker.component';
+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 { AuditLogsEntriesComponent } from '@app/components/audit-logs-entries/audit-logs-entries.component';
+import { GraphLegendComponent } from '@app/components/graph-legend/graph-legend.component';
+import { HorizontalHistogramComponent } from '@app/components/horizontal-histogram/horizontal-histogram.component';
+import { GraphTooltipComponent } from '@app/components/graph-tooltip/graph-tooltip.component';
+import { GraphLegendItemComponent } from '@app/components/graph-legend-item/graph-legend-item.component';
+import { TimeLineGraphComponent } from '@app/components/time-line-graph/time-line-graph.component';
+import { ContextMenuComponent } from '@app/components/context-menu/context-menu.component';
+import { HistoryItemControlsComponent } from '@app/components/history-item-controls/history-item-controls.component';
+import { LogIndexFilterComponent } from '@app/components/log-index-filter/log-index-filter.component';
-import {TimeZoneAbbrPipe} from '@app/pipes/timezone-abbr.pipe';
-import {TimerSecondsPipe} from '@app/pipes/timer-seconds.pipe';
-import {ComponentLabelPipe} from '@app/pipes/component-label';
-import {AppRoutingModule} from '@app/app-routing.module';
-import {AuthGuardService} from '@app/services/auth-guard.service';
-import {BreadcrumbsComponent} from '@app/components/breadrumbs/breadcrumbs.component';
-import {ClusterFilterComponent } from '@app/components/cluster-filter/cluster-filter.component';
-import {ClusterSelectionService} from '@app/services/storage/cluster-selection.service';
-import {TranslateService as AppTranslateService} from '@app/services/translate.service';
-import {RoutingUtilsService} from '@app/services/routing-utils.service';
-import {TabGuard} from '@app/services/tab.guard';
-import {FilterHistoryIndexGuard} from '@app/services/filter-history.guard';
-import {LogsBreadcrumbsResolverService} from '@app/services/logs-breadcrumbs-resolver.service';
-import {LogsFilteringUtilsService} from '@app/services/logs-filtering-utils.service';
-import {LogsStateService} from '@app/services/storage/logs-state.service';
-import {LoginScreenGuardService} from '@app/services/login-screen-guard.service';
+import { TimeZoneAbbrPipe } from '@app/pipes/timezone-abbr.pipe';
+import { TimerSecondsPipe } from '@app/pipes/timer-seconds.pipe';
+import { ComponentLabelPipe } from '@app/pipes/component-label';
+import { RepoLabelPipe } from '@app/pipes/repo-label';
+import { AuditLogFieldLabelPipe } from '@app/pipes/audit-log-field-label.pipe';
+import { AppRoutingModule } from '@app/app-routing.module';
+import { AuthGuardService } from '@app/services/auth-guard.service';
+import { BreadcrumbsComponent } from '@app/components/breadrumbs/breadcrumbs.component';
+import { ClusterFilterComponent } from '@app/components/cluster-filter/cluster-filter.component';
+import { ClusterSelectionService } from '@app/services/storage/cluster-selection.service';
+import { TranslateService as AppTranslateService } from '@app/services/translate.service';
+import { RoutingUtilsService } from '@app/services/routing-utils.service';
+import { TabGuard } from '@app/services/tab.guard';
+import { FilterHistoryIndexGuard } from '@app/services/filter-history.guard';
+import { LogsBreadcrumbsResolverService } from '@app/services/logs-breadcrumbs-resolver.service';
+import { LogsFilteringUtilsService } from '@app/services/logs-filtering-utils.service';
+import { LogsStateService } from '@app/services/storage/logs-state.service';
+import { LoginScreenGuardService } from '@app/services/login-screen-guard.service';
import { AuthEffects } from '@app/store/effects/auth.effects';
import { NotificationEffects } from '@app/store/effects/notification.effects';
import { FilterHistoryManagerComponent } from './components/filter-history-manager/filter-history-manager.component';
+import { AuditLogReposEffects } from './store/effects/audit-log-repos.effects';
@NgModule({
declarations: [
@@ -158,6 +161,8 @@ import { FilterHistoryManagerComponent } from './components/filter-history-manag
TimeZoneAbbrPipe,
TimerSecondsPipe,
ComponentLabelPipe,
+ RepoLabelPipe,
+ AuditLogFieldLabelPipe,
BreadcrumbsComponent,
ClusterFilterComponent,
FilterHistoryManagerComponent
@@ -193,7 +198,8 @@ import { FilterHistoryManagerComponent } from './components/filter-history-manag
AppRoutingModule,
EffectsModule.run(AuthEffects),
- EffectsModule.run(NotificationEffects)
+ EffectsModule.run(NotificationEffects),
+ EffectsModule.run(AuditLogReposEffects)
],
providers: [
diff --git a/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts b/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts
index af6a9db..3c13ae4 100644
--- a/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts
+++ b/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts
@@ -32,13 +32,26 @@ import {ServiceInjector} from '@app/classes/service-injector';
import {UtilsService} from '@app/services/utils.service';
import {Subscription} from 'rxjs/Subscription';
+export const graphColors = [
+ '#41bfae',
+ '#79e3d1',
+ '#63c2e5',
+ '#c4aeff',
+ '#b991d9',
+ '#ffb9bf',
+ '#ffae65',
+ '#f6d151',
+ '#a7cf82',
+ '#abdfd5'
+];
+
export class GraphComponent implements AfterViewInit, OnChanges, OnInit, OnDestroy {
@Input()
data: HomogeneousObject<HomogeneousObject<number>> = {};
@Input()
- svgId: string = 'graph-svg';
+ svgId = 'graph-svg';
@Input()
margin: GraphMarginOptions = {
@@ -164,7 +177,7 @@ export class GraphComponent implements AfterViewInit, OnChanges, OnInit, OnDestr
* Ordered array of color strings for data representation
* @type {string[]}
*/
- protected orderedColors: string[];
+ protected orderedColors: string[] = graphColors;
/**
* This property is to hold the data of the bar where the mouse is over.
@@ -260,6 +273,7 @@ export class GraphComponent implements AfterViewInit, OnChanges, OnInit, OnDestr
}
protected setLegendItems(): void {
+ this.setColors();
if (this.colors && this.labels) {
this.legendItems = Object.keys(this.labels).map((key: string) => Object.assign({}, {
label: this.labels[key],
@@ -268,31 +282,27 @@ export class GraphComponent implements AfterViewInit, OnChanges, OnInit, OnDestr
}
}
- protected setup(): void {
- const margin = this.margin;
- if (this.utils.isEmptyObject(this.colors)) {
- // set default color scheme for different values if no custom colors specified
+ protected getOrderedColorsByColors(colors: {[key: string]: string}): string[] {
+ const keys = Object.keys(colors);
+ return keys.reduce((orderedColors: string[], key: string): string[] => [...orderedColors, colors[key]], []);
+ }
+
+ protected setColors(): void {
+ if (this.utils.isEmptyObject(this.colors) && this.orderedColors && this.orderedColors.length) {
const keys = Object.keys(this.labels);
- const keysCount = keys.length;
- const specterLength = keysCount > 2 ? keysCount : 3; // length of minimal available spectral scheme is 3
- let colorsArray;
- if (keysCount > 2) {
- colorsArray = Array.from(d3sc.schemeSpectral[keysCount]);
- } else {
- const minimalColorScheme = Array.from(d3sc.schemeSpectral[specterLength]);
- colorsArray = minimalColorScheme.slice(0, keysCount);
- }
- this.orderedColors = colorsArray;
this.colors = keys.reduce((currentObject: HomogeneousObject<string>, currentKey: string, index: number) => {
return Object.assign(currentObject, {
- [currentKey]: colorsArray[index]
+ [currentKey]: this.orderedColors[index]
});
}, {});
- } else {
- const keysWithColors = this.colors,
- keys = Object.keys(keysWithColors);
- this.orderedColors = keys.reduce((array: string[], key: string): string[] => [...array, keysWithColors[key]], []);
+ } else if (!this.utils.isEmptyObject(this.colors)) {
+ this.orderedColors = this.getOrderedColorsByColors(this.colors);
}
+ }
+
+ protected setup(): void {
+ const margin = this.margin;
+ this.setColors();
this.width = this.graphContainer.clientWidth - margin.left - margin.right;
const xScale = this.isTimeGraph ? d3.scaleTime() : d3.scaleLinear();
const yScale = d3.scaleLinear();
@@ -470,6 +480,8 @@ export class GraphComponent implements AfterViewInit, OnChanges, OnInit, OnDestr
}
this.tooltipOnTheLeft = left < relativeMousePosition[0];
this.tooltipPosition = {left, top};
+ } else {
+ this.tooltipPosition = undefined;
}
};
diff --git a/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.spec.ts b/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.spec.ts
index 05f80a7..369201e 100644
--- a/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.spec.ts
+++ b/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.spec.ts
@@ -40,14 +40,16 @@ describe('LogsTableComponent', () => {
];
beforeEach(() => {
- component.displayedColumns = [
+ component.columns = [
{
label: 'l0',
- value: 'v0'
+ value: 'v0',
+ isChecked: true
},
{
label: 'l1',
- value: 'v1'
+ value: 'v1',
+ isChecked: true
}
];
});
@@ -58,4 +60,4 @@ describe('LogsTableComponent', () => {
});
});
});
-});
\ No newline at end of file
+});
diff --git a/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.ts b/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.ts
index 0b8866a..ebe5d61 100644
--- a/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.ts
+++ b/ambari-logsearch-web/src/app/classes/components/logs-table/logs-table-component.ts
@@ -16,20 +16,13 @@
* 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);
- }
- }
+import { Input, OnInit } 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 OnInit {
@Input()
logs: ServiceLog[] | AuditLog[] = [];
@@ -40,12 +33,33 @@ export class LogsTableComponent implements OnChanges {
filtersForm: FormGroup;
@Input()
- totalCount: number = 0;
+ totalCount = 0;
+
+ get displayedColumns(): ListItem[] {
+ return this.columns ? this.columns.filter((column: ListItem): boolean => column.isChecked) : [];
+ };
+
+ columnLabels: {[key: string]: string} = {};
+
+ ngOnInit() {
+ this.mapColumnLabelsToLocalCopy(this.columns);
+ }
- displayedColumns: ListItem[] = [];
+ mapColumnLabelsToLocalCopy(columns) {
+ this.columnLabels = (columns || []).reduce( (labels, column): {[key: string]: string} => {
+ return {
+ ...labels,
+ [column.value]: column.label || column.value
+ };
+ }, {});
+ }
isColumnDisplayed(key: string): boolean {
return this.displayedColumns.some((column: ListItem): boolean => column.value === key);
}
+ getColumnLabel(key: string): string {
+ return this.columnLabels[key] || key;
+ }
+
}
diff --git a/ambari-logsearch-web/src/app/classes/models/audit-log.ts b/ambari-logsearch-web/src/app/classes/models/audit-log.ts
index 380f14f..085dc56 100644
--- a/ambari-logsearch-web/src/app/classes/models/audit-log.ts
+++ b/ambari-logsearch-web/src/app/classes/models/audit-log.ts
@@ -18,6 +18,8 @@
import {Log} from '@app/classes/models/log';
+export const commonFieldNames: string[] = ['evtTime', 'repo', 'reqUser', 'action'];
+
export interface AuditLog extends Log {
policy?: string;
reason?: string;
diff --git a/ambari-logsearch-web/src/app/classes/models/store.ts b/ambari-logsearch-web/src/app/classes/models/store.ts
index 3811de1..69aa2e2 100644
--- a/ambari-logsearch-web/src/app/classes/models/store.ts
+++ b/ambari-logsearch-web/src/app/classes/models/store.ts
@@ -28,7 +28,7 @@ import { Graph } from '@app/classes/models/graph';
import { NodeItem } from '@app/classes/models/node-item';
import { UserConfig } from '@app/classes/models/user-config';
import { LogTypeTab } from '@app/classes/models/log-type-tab';
-import { LogField } from '@app/classes/object';
+import { LogField, AuditLogsFieldSet } from '@app/classes/object';
import { UtilsService } from '@app/services/utils.service';
import { NotificationInterface } from '@modules/shared/interfaces/notification.interface';
import { LogsState } from '@app/classes/models/logs-state';
@@ -36,6 +36,7 @@ import { DataAvaibilityStatesModel } from '@app/modules/app-load/models/data-ava
import * as auth from '@app/store/reducers/auth.reducers';
import * as filterHistory from '@app/store/reducers/filter-history.reducers';
+import * as auditLogRepos from '@app/store/reducers/audit-log-repos.reducers';
const storeActions = {
'ARRAY.ADD': 'ADD',
@@ -66,13 +67,14 @@ export interface AppStore {
clusters: string[];
components: NodeItem[];
serviceLogsFields: LogField[];
- auditLogsFields: LogField[];
+ auditLogsFields: AuditLogsFieldSet;
tabs: LogTypeTab[];
notifications: NotificationInterface[];
logsState: LogsState;
dataAvailabilityStates: DataAvaibilityStatesModel;
auth: auth.State;
filterHistory: filterHistory.FilterHistoryState;
+ auditLogRepos: auditLogRepos.AuditLogRepo[];
}
export class ModelService {
diff --git a/ambari-logsearch-web/src/app/classes/object.ts b/ambari-logsearch-web/src/app/classes/object.ts
index 2cb39b1..146ec1a 100644
--- a/ambari-logsearch-web/src/app/classes/object.ts
+++ b/ambari-logsearch-web/src/app/classes/object.ts
@@ -40,9 +40,13 @@ export interface LogField {
/**
* This is an interface for the service and audit log fields.
*/
-export interface AuditFieldsDefinitionSet {
+export interface AuditLogsFieldSet {
defaults: LogField[],
overrides: {
[key: string]: LogField[]
}
}
+export enum AuditLogsFieldsSetRootKeys {
+ DEFAULTS = 'defaults',
+ OVERRIDES = 'overrides'
+};
diff --git a/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.html b/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.html
index 6ebb92e..e94b14f 100644
--- a/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.html
+++ b/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.html
@@ -18,7 +18,7 @@
<tabs [items]="tabs" (tabSwitched)="setActiveTab($event)"></tabs>
<ng-container [ngSwitch]="activeTab">
<audit-logs-table *ngSwitchCase="'logs'" [totalCount]="totalCount" [logs]="logs" [columns]="columns"
- [filtersForm]="filtersForm"></audit-logs-table>
+ [filtersForm]="filtersForm" [commonFieldNames]="commonFieldNames"></audit-logs-table>
<div *ngSwitchCase="'summary'" class="row">
<collapsible-panel commonTitle="{{'logs.topUsers' | translate: usersGraphTitleParams}}" class="col-md-6">
<horizontal-histogram [data]="topUsersGraphData" [allowFractionalXTicks]="false"
diff --git a/ambari-logsearch-web/src/styles.less b/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.less
similarity index 71%
copy from ambari-logsearch-web/src/styles.less
copy to ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.less
index e3ecbb7..863a0df 100644
--- a/ambari-logsearch-web/src/styles.less
+++ b/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.less
@@ -15,17 +15,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@import './app/modules/shared/main';
-body {
- background-color: @main-background-color;
-}
-.initial-color {
- color: initial;
-}
-/** Override Bootstrap rules **/
-.btn-link {
- &:hover, &:focus {
- text-decoration: none;
+:host {
+ display: block;
+ /deep/ tabs {
+ display: block;
+ margin: 0;
+ ul.nav.nav-tabs {
+ margin: 0;
+ > li.active > a,
+ > li.active > a:focus,
+ > li.active > a:hover {
+ background-color: transparent;
+ }
+ }
+ }
+ /deep/ audit-logs-table {
+ position: relative;
+ top: -2rem;
}
}
diff --git a/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.ts b/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.ts
index c0ab63d..43b9ed1 100644
--- a/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.ts
+++ b/ambari-logsearch-web/src/app/components/audit-logs-entries/audit-logs-entries.component.ts
@@ -15,24 +15,26 @@
* limitations under the License.
*/
-import {Component, Input} from '@angular/core';
-import {FormGroup} from '@angular/forms';
-import {GraphEmittedEvent} from '@app/classes/graph';
-import {ListItem} from '@app/classes/list-item';
-import {HomogeneousObject} from '@app/classes/object';
-import {AuditLog} from '@app/classes/models/audit-log';
-import {LogTypeTab} from '@app/classes/models/log-type-tab';
-import {LogsContainerService} from '@app/services/logs-container.service';
+import { Component, Input } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+import { GraphEmittedEvent } from '@app/classes/graph';
+import { ListItem } from '@app/classes/list-item';
+import { HomogeneousObject, AuditLogsFieldSet, LogField, AuditLogsFieldsSetRootKeys } from '@app/classes/object';
+import { AuditLog } from '@app/classes/models/audit-log';
+import { LogTypeTab } from '@app/classes/models/log-type-tab';
+import { LogsContainerService } from '@app/services/logs-container.service';
+import { Store } from '@ngrx/store';
+import { AppStore } from '@app/classes/models/store';
+import { selectAuditLogsFieldState } from '@app/store/selectors/audit-logs-fields.selectors';
+import { Observable } from 'rxjs/Observable';
@Component({
selector: 'audit-logs-entries',
- templateUrl: './audit-logs-entries.component.html'
+ templateUrl: './audit-logs-entries.component.html',
+ styleUrls: ['./audit-logs-entries.component.less']
})
export class AuditLogsEntriesComponent {
- constructor(private logsContainer: LogsContainerService) {
- }
-
@Input()
logs: AuditLog[] = [];
@@ -43,15 +45,17 @@ export class AuditLogsEntriesComponent {
filtersForm: FormGroup;
@Input()
- totalCount: number = 0;
+ totalCount = 0;
+
+ @Input()
+ commonFieldNames: string[] = [];
tabs: LogTypeTab[] = [
{
id: 'summary',
isActive: true,
label: 'common.summary'
- },
- {
+ }, {
id: 'logs',
isActive: false,
label: 'common.logs'
@@ -62,19 +66,19 @@ export class AuditLogsEntriesComponent {
* Id of currently active tab (Summary or Logs)
* @type {string}
*/
- activeTab: string = 'summary';
+ activeTab = 'summary';
/**
* 'left' CSS property value for context menu dropdown
* @type {number}
*/
- contextMenuLeft: number = 0;
+ contextMenuLeft = 0;
/**
* 'top' CSS property value for context menu dropdown
* @type {number}
*/
- contextMenuTop: number = 0;
+ contextMenuTop = 0;
readonly usersGraphTitleParams = {
number: this.logsContainer.topUsersCount
@@ -84,13 +88,39 @@ export class AuditLogsEntriesComponent {
number: this.logsContainer.topResourcesCount
};
- private readonly resourceFilterParameterName: string = 'resource';
+ private readonly resourceFilterParameterName = 'resource';
/**
* Text for filtering be resource type (set from Y axis tick of Resources chart)
* @type {string}
*/
- private selectedResource: string = '';
+ private selectedResource = '';
+
+ fields$: Observable<AuditLogsFieldSet> = this.store.select(selectAuditLogsFieldState);
+
+ columns$: Observable<ListItem[]> = this.fields$.map((fieldSet: AuditLogsFieldSet): ListItem[] => {
+ let columns: {[key: string]: string} = {// flattening the audit logs field set to field-name: field-label map
+ ...this.getNameLabelMapFromLogFieldList(fieldSet[AuditLogsFieldsSetRootKeys.DEFAULTS]),
+ ...(Object.keys(fieldSet[AuditLogsFieldsSetRootKeys.OVERRIDES]).reduce(
+ (currentColumns: {[key: string]: string}, componentName: string) => ({
+ ...currentColumns,
+ ...this.getNameLabelMapFromLogFieldList(fieldSet[AuditLogsFieldsSetRootKeys.OVERRIDES][componentName])
+ }), {}
+ ))
+ };
+ return Object.keys(columns).reduce((listItems: ListItem[], fieldName: string): ListItem[] => ([ // creating ListItem too feed the dropdown
+ ...listItems,
+ {
+ value: fieldName,
+ label: columns[fieldName]
+ }
+ ]), []);
+ });
+
+ constructor(
+ private logsContainer: LogsContainerService,
+ private store: Store<AppStore>
+ ) {}
get topResourcesGraphData(): HomogeneousObject<HomogeneousObject<number>> {
return this.logsContainer.topResourcesGraphData;
@@ -108,6 +138,15 @@ export class AuditLogsEntriesComponent {
return this.logsContainer.queryContextMenuItems;
}
+ getNameLabelMapFromLogFieldList(logFieldList: LogField[]): {[key: string]: string} {
+ return logFieldList.reduce(
+ (map: {[key: string]: string}, field: LogField) => ({
+ ...map,
+ [field.name]: field.label || field.name
+ }), {}
+ );
+ }
+
setActiveTab(tab: LogTypeTab): void {
this.activeTab = tab.id;
}
diff --git a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html
index f970726..79ca25d 100644
--- a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html
+++ b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html
@@ -15,41 +15,55 @@
limitations under the License.
-->
-<dropdown-button class="pull-right" label="{{'logs.columns' | translate}}" (selectItem)="updateSelectedColumns($event)"
- [options]="columns" [isRightAlign]="true" [isMultipleChoice]="true"></dropdown-button>
-<form *ngIf="logs && logs.length" [formGroup]="filtersForm" class="row pull-right">
- <filter-dropdown class="col-md-12" label="{{filters.auditLogsSorting.label | translate}}"
- formControlName="auditLogsSorting" [options]="filters.auditLogsSorting.options"
- [isRightAlign]="true" [showCommonLabelWithSelection]="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-template #fieldTemplate let-value let-field="field" let-component="component">
+ <div class="audit-logs-list-column dashrow-column" [class.audit-logs-list-column-common]="isCommonField(field)" [ngClass]="field"
+ [class.data-not-available]="!value">
+ <div class="audit-logs-list-column-value dashrow-value">
+ <ng-container [ngSwitch]="field">
+ <span class="date-time-format" *ngSwitchCase="'evtTime'">{{value | amTz: timeZone | amDateFormat: timeFormat}}</span>
+ <span *ngSwitchCase="'repo'">{{value | repoLabel | async}}</span>
+ <span *ngSwitchCase="'type'">{{value | componentLabel | async}}</span>
+ <span *ngSwitchDefault class="default-format">{{value || ('common.notAvailable' | translate)}}</span>
+ </ng-container>
+ </div>
+ <div class="audit-logs-list-column-label dashrow-label">{{(field | auditLogFieldLabel:component | async) | translate}}</div>
+ </div>
+</ng-template>
+
+<div class="audit-logs-list-controls">
+ <form *ngIf="logs && logs.length" [formGroup]="filtersForm" class="row pull-right">
+ <filter-dropdown class="col-md-12" label="{{filters.auditLogsSorting.label | translate}}"
+ formControlName="auditLogsSorting" [options]="filters.auditLogsSorting.options"
+ [isRightAlign]="true" [showCommonLabelWithSelection]="true"></filter-dropdown>
+ </form>
+ <dropdown-button class="pull-right" label="{{'logs.columns' | translate}}" (selectItem)="updateSelectedColumns($event)" [useClearToDefaultSelection]="true"
+ [options]="columns" [isRightAlign]="true" [isMultipleChoice]="true" [useDropDownLocalFilter]="true" [closeOnSelection]="false"></dropdown-button>
+</div>
+
+<section class="audit-logs-list-container">
+ <div class="audit-logs-list-body dashrow-container">
+ <div *ngFor="let log of logs" class="audit-logs-list-row dashrow-row-wrapper" [ngClass]="log.repo">
+ <div class="repo-initial dashrow-initial">{{log.repo[0]}}</div>
+ <div class="audit-logs-list-row dashrow-row">
+ <div *ngIf="displayedCommonColumns.length" class="dashrow-column-group dashrow-column-group-fixed-left">
+ <ng-container *ngFor="let field of displayedCommonColumns">
+ <ng-container *ngIf="log[field] !== undefined">
+ <ng-container *ngTemplateOutlet="fieldTemplate; context:{$implicit: log[field], field: field, component: log.type}"></ng-container>
+ </ng-container>
</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>
+ </div>
+ <div *ngIf="displayedNotCommonColumns.length" class="dashrow-column-group">
+ <ng-container *ngFor="let field of displayedNotCommonColumns">
+ <ng-container *ngIf="log[field] !== undefined">
+ <ng-container *ngTemplateOutlet="fieldTemplate; context:{$implicit: log[field], field: field, component: log.type}"></ng-container>
+ </ng-container>
</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>
+ </div>
</div>
-</div>
+ <footer class="audit-logs-list-footer">
+ <pagination class="col-md-12" *ngIf="logs && logs.length" [totalCount]="totalCount" [filtersForm]="filtersForm" [filterInstance]="filters.pageSize"
+ [currentCount]="logs.length"></pagination>
+ </footer>
+</section>
diff --git a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less
index d9b0a10..5533807 100644
--- a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less
+++ b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less
@@ -16,6 +16,86 @@
* limitations under the License.
*/
-th {
- text-transform: uppercase;
+@import '../../modules/shared/variables';
+@import '../../modules/shared/mixins';
+
+@repos: 'ambari', 'hdfs', 'yarn', 'default';
+@repoColors: {
+ ambari: #CB932A;
+ hdfs: #21A2C2;
+ yarn: #269C1E;
+ default: @fluid-gray-2;
+};
+
+@initial-ambari-color: #C19544;
+@initial-hdfs-color: #48A4BB;
+@initial-yarn-color: #479D2F;
+@initial-default-color: @fluid-gray-2;
+@initial-size: 3em;
+
+:host {
+ display: block;
+ padding: 0 2rem;
+
+ .audit-logs-list-controls {
+ justify-content: flex-end;
+ display: flex;
+ width: 100%;
+ /deep/ button {
+ padding-bottom: 0;
+ }
+ }
+
+ .dashrow-initial {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ text-transform: uppercase;
+ }
+
+ .dashrow-column {
+ padding: 0 1rem;
+ &.evtTime {
+ max-width: 22rem;
+ min-width: 22rem;
+ }
+ &.repo {
+ max-width: 15rem;
+ min-width: 15rem;
+ }
+ &.action {
+ max-width: 23rem;
+ min-width: 23rem;
+ }
+ &.reqUser {
+ max-width: 10rem;
+ min-width: 10rem;
+ }
+ .dashrow-value {
+ span {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+ &.data-not-available {
+ .dashrow-value {
+ color: @fluid-gray-2;
+ }
+ }
+ }
+
+ each(@repoColors, {
+ .@{key} .dashrow-initial {
+ background-color: @value;
+ &:before {
+ border-bottom-color: @value;
+ }
+ &:after {
+ border-top-color: @value;
+ }
+ }
+ });
+
}
diff --git a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts
index 60c6e9b..a698bdd 100644
--- a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts
+++ b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts
@@ -58,6 +58,10 @@ import { EffectsModule } from '@ngrx/effects';
import { AuthEffects } from '@app/store/effects/auth.effects';
import { NotificationEffects } from '@app/store/effects/notification.effects';
+import {ComponentLabelPipe} from '@app/pipes/component-label';
+import { RepoLabelPipe } from '@app/pipes/repo-label';
+import { AuditLogFieldLabelPipe } from '@app/pipes/audit-log-field-label.pipe';
+
describe('AuditLogsTableComponent', () => {
let component: AuditLogsTableComponent;
let fixture: ComponentFixture<AuditLogsTableComponent>;
@@ -65,6 +69,9 @@ describe('AuditLogsTableComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
+ ComponentLabelPipe,
+ RepoLabelPipe,
+ AuditLogFieldLabelPipe,
AuditLogsTableComponent,
PaginationComponent,
DropdownListComponent
diff --git a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts
index fa5b1c5..5653254 100644
--- a/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts
+++ b/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts
@@ -16,27 +16,52 @@
* limitations under the License.
*/
-import {Component} from '@angular/core';
+import {Component, Input, OnInit, OnDestroy} from '@angular/core';
import {ListItem} from '@app/classes/list-item';
import {LogsTableComponent} from '@app/classes/components/logs-table/logs-table-component';
import {LogsContainerService} from '@app/services/logs-container.service';
+import { Store } from '@ngrx/store';
+import { AppStore } from '@app/classes/models/store';
+import { Observable } from 'rxjs/Observable';
+import { selectAuditLogsFieldState } from '@app/store/selectors/audit-logs-fields.selectors';
+import { LogField, AuditLogsFieldSet } from '@app/classes/object';
+import { Subject } from 'rxjs/Subject';
@Component({
selector: 'audit-logs-table',
templateUrl: './audit-logs-table.component.html',
styleUrls: ['./audit-logs-table.component.less']
})
-export class AuditLogsTableComponent extends LogsTableComponent {
+export class AuditLogsTableComponent extends LogsTableComponent implements OnInit, OnDestroy {
- constructor(private logsContainer: LogsContainerService) {
- super();
- }
+ @Input()
+ commonFieldNames: string[];
readonly customProcessedColumns: string[] = ['evtTime'];
- readonly timeFormat: string = 'YYYY-MM-DD HH:mm:ss,SSS';
+ readonly timeFormat = 'YYYY-MM-DD HH:mm:ss';
+
+ private readonly logsType = 'auditLogs';
+
+ private localCopyOfFields: AuditLogsFieldSet;
+
+ private destroyed$: Subject<boolean> = new Subject();
- private readonly logsType: string = 'auditLogs';
+ private fields$: Observable<AuditLogsFieldSet> = this.store.select(selectAuditLogsFieldState);
+
+ get displayedCommonColumns(): string[] {
+ return this.commonFieldNames.reduce(
+ (fieldNames: string[], fieldName: string): string[] => {
+ return this.isColumnDisplayed(fieldName) ? [...fieldNames, fieldName] : fieldNames;
+ },
+ []
+ );
+ }
+
+ get displayedNotCommonColumns(): string[] {
+ return this.displayedColumns.filter((column: ListItem) => this.commonFieldNames.indexOf(column.value) === -1)
+ .map((column: ListItem) => column.value);
+ }
get filters(): any {
return this.logsContainer.filters;
@@ -46,6 +71,26 @@ export class AuditLogsTableComponent extends LogsTableComponent {
return this.logsContainer.timeZone;
}
+ constructor(
+ private logsContainer: LogsContainerService,
+ private store: Store<AppStore>
+ ) {
+ super();
+ }
+
+ ngOnInit() {
+ this.fields$.takeUntil(this.destroyed$).subscribe(this.handleFieldsData);
+ }
+
+ ngOnDestroy() {
+ this.destroyed$.next(true);
+ this.destroyed$.complete();
+ }
+
+ handleFieldsData = (auditLogFields: AuditLogsFieldSet) => {
+ this.localCopyOfFields = auditLogFields;
+ }
+
getColumnByName(name: string): ListItem | undefined {
return this.columns.find((column: ListItem): boolean => column.value === name);
}
@@ -54,4 +99,8 @@ export class AuditLogsTableComponent extends LogsTableComponent {
this.logsContainer.updateSelectedColumns(columns, this.logsType);
}
+ isCommonField(fieldName: string): boolean {
+ return this.commonFieldNames.indexOf(fieldName) > -1;
+ }
+
}
diff --git a/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less b/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
index 79d25f3..3908604 100644
--- a/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
+++ b/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
@@ -37,8 +37,7 @@
}
&.panel-collapsed {
.panel-body {
- height: 0;
- overflow: hidden;
+ display: none;
}
}
}
diff --git a/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.ts b/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.ts
index 5e86bfa..585daa5 100644
--- a/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.ts
+++ b/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.ts
@@ -15,11 +15,11 @@
* limitations under the License.
*/
-import {Component, Input} from '@angular/core';
+import { Component, Input } from '@angular/core';
enum Side {
- LEFT = "left",
- RIGHT = "right"
+ LEFT = 'left',
+ RIGHT = 'right'
}
/**
@@ -39,7 +39,7 @@ export class CollapsiblePanelComponent {
* @type {string}
*/
@Input()
- commonTitle: string = '';
+ commonTitle = '';
/**
* The panel's title for the opened state
@@ -67,7 +67,7 @@ export class CollapsiblePanelComponent {
* @type {boolean}
*/
@Input()
- isCollapsed: boolean = false;
+ isCollapsed = false;
/**
* The goal is to handle the click event of the collapse link/button. It will simply call the inside logic to toggle
diff --git a/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html b/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html
index 724b0a4..10d36e0 100644
--- a/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html
+++ b/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.html
@@ -66,6 +66,17 @@
[isDisabled]="isServiceLogsFileView$ | async"
additionalLabelComponentSetter="getDataForComponentsNodeBar"></filter-button>
+ <filter-button *ngIf="isFilterConditionDisplayed('repos')"
+ formControlName="repos"
+ [subItems]="filters.repos.options"
+ label="{{filters.repos.label | translate}}"
+ [useDropDownLocalFilter]="true"
+ [isMultipleChoice]="true"
+ [iconClass]="filters.repos.iconClass"
+ [isRightAlign]="true"
+ [class.disabled]="isServiceLogsFileView$ | async"
+ [isDisabled]="isServiceLogsFileView$ | async"></filter-button>
+
<filter-button *ngIf="isFilterConditionDisplayed('levels')"
formControlName="levels"
label="{{filters.levels.label | translate}}"
diff --git a/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.html b/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.html
index e756af6..56431b1 100644
--- a/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.html
+++ b/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.html
@@ -15,5 +15,4 @@
limitations under the License.
-->
-<graph-legend-item *ngFor="let item of items" label="{{item.label | translate}}"
- color="{{item.color}}"></graph-legend-item>
+<graph-legend-item *ngFor="let item of items" label="{{item.label | translate}}" color="{{item.color}}"></graph-legend-item>
diff --git a/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.ts b/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.ts
index e273d4e..2868346 100644
--- a/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.ts
+++ b/ambari-logsearch-web/src/app/components/graph-legend/graph-legend.component.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {Component, Input} from '@angular/core';
+import { Component, Input } from '@angular/core';
@Component({
selector: 'graph-legend',
@@ -27,6 +27,6 @@ export class GraphLegendComponent {
items = [];
@Input()
- labelClass: string = 'initial-color';
+ labelClass = 'initial-color';
}
diff --git a/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.html b/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.html
index 015013f..27d0916 100644
--- a/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.html
+++ b/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.html
@@ -18,5 +18,5 @@
<div #graphContainer></div>
<graph-legend class="col-md-12" [items]="legendItems"></graph-legend>
<graph-tooltip #tooltip [data]="tooltipInfo.data" [title]="tooltipInfo.title" [ngClass]="{'hide': !tooltipInfo.data}"
- [style.top]="tooltipInfo.data ? tooltipPosition.top + 'px' : ''"
- [style.left]="tooltipInfo.data ? tooltipPosition.left + 'px' : ''"></graph-tooltip>
+ [style.top]="tooltipPosition ? tooltipPosition.top + 'px' : ''"
+ [style.left]="tooltipPosition ? tooltipPosition.left + 'px' : ''"></graph-tooltip>
diff --git a/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.ts b/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.ts
index 8cc3149..27c628c 100644
--- a/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.ts
+++ b/ambari-logsearch-web/src/app/components/horizontal-histogram/horizontal-histogram.component.ts
@@ -15,10 +15,10 @@
* limitations under the License.
*/
-import {Component, Input} from '@angular/core';
+import { Component, Input } from '@angular/core';
import * as d3 from 'd3';
-import {GraphComponent} from '@app/classes/components/graph/graph.component';
-import {HomogeneousObject} from '@app/classes/object';
+import { GraphComponent } from '@app/classes/components/graph/graph.component';
+import { HomogeneousObject } from '@app/classes/object';
@Component({
selector: 'horizontal-histogram',
@@ -32,33 +32,33 @@ export class HorizontalHistogramComponent extends GraphComponent {
* @type {number}
*/
@Input()
- barSize: number = 5;
+ barSize = 5;
rowsCount: number;
- readonly reverseYRange: boolean = true;
+ readonly reverseYRange = true;
protected populate(): void {
- const barSize = this.barSize,
- data = this.data,
- yValues = Object.keys(data),
- keys = Object.keys(this.labels),
- rowsCount = yValues.reduce((currentCount: number, currentKey: string): number => {
+ const barSize = this.barSize;
+ const data = this.data;
+ const yValues = Object.keys(data);
+ const keys = Object.keys(this.labels);
+ const rowsCount = yValues.reduce((currentCount: number, currentKey: string): number => {
return currentCount + Object.keys(this.data[currentKey]).length;
- }, 0),
- formattedData = yValues.reduce((currentData, currentKey: string) => {
- const currentValues = data[currentKey],
- currentObjects = keys.map((key: string): HomogeneousObject<number> => {
- return {
- [key]: currentValues[key] || 0
- };
- });
- return [...currentData, Object.assign({
- tick: currentKey
- }, ...currentObjects)];
- }, []),
- layers = d3.stack().keys(keys)(formattedData),
- formattedLayers = d3.transpose<any>(layers);
+ }, 0);
+ const formattedData = yValues.reduce((currentData, currentKey: string) => {
+ const currentValues = data[currentKey],
+ currentObjects = keys.map((key: string): HomogeneousObject<number> => {
+ return {
+ [key]: currentValues[key] || 0
+ };
+ });
+ return [...currentData, Object.assign({
+ tick: currentKey
+ }, ...currentObjects)];
+ }, []);
+ const layers = d3.stack().keys(keys)(formattedData);
+ const formattedLayers = d3.transpose<any>(layers);
this.rowsCount = rowsCount;
@@ -78,7 +78,8 @@ export class HorizontalHistogramComponent extends GraphComponent {
if (item [0] !== item[1]) {
return this.yScale(i++) - this.barSize / 2;
}
- }).attr('height', item => item[0] === item[1] ? '0' : barSize.toString())
+ })
+ .attr('height', item => item[0] === item[1] ? '0' : barSize.toString())
.attr('width', item => this.xScale(item[1]) - this.xScale(item[0]))
.style('fill', (item, index) => this.orderedColors[index])
.on('mouseover', this.handleMouseOver)
diff --git a/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html b/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
index 1add8a3..e8c1e4b 100644
--- a/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
+++ b/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
@@ -51,12 +51,12 @@
[filtersForm]="filtersForm" [class.loading]="logsContainerService.isLogsRequestInProgress$ | async"></service-logs-table>
</ng-container>
<ng-container *ngSwitchCase="'auditLogs'">
- <collapsible-panel commonTitle="logs.duration">
+ <collapsible-panel commonTitle="logs.duration" openTitle="logs.hideGraph" collapsedTitle="logs.showGraph">
<time-line-graph (selectArea)="setCustomTimeRange($event[0], $event[1])" [data]="auditLogsGraphData"
[allowFractionalYTicks]="false" [skipZeroValuesInTooltip]="false" svgId="audit-logs-graph"
[class.loading]="logsContainerService.isGraphRequestInProgress$ | async"></time-line-graph>
</collapsible-panel>
- <audit-logs-entries [totalCount]="totalCount" [logs]="auditLogs | async" [columns]="auditLogsColumns | async"
+ <audit-logs-entries [totalCount]="totalCount" [logs]="auditLogs | async" [columns]="auditLogsColumns | async" [commonFieldNames]="auditLogsCommonFieldNames"
[filtersForm]="filtersForm" [class.loading]="logsContainerService.isLogsRequestInProgress$ | async"></audit-logs-entries>
</ng-container>
</ng-container>
diff --git a/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts b/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
index ea27163..4db47a2 100644
--- a/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
+++ b/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
@@ -39,6 +39,8 @@ import { LogsFilteringUtilsService } from '@app/services/logs-filtering-utils.se
import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { commonFieldNames as auditLogsCommonFieldNames } from '@app/classes/models/audit-log';
+
@Component({
selector: 'logs-container',
templateUrl: './logs-container.component.html',
@@ -88,6 +90,10 @@ export class LogsContainerComponent implements OnInit, OnDestroy {
isServiceLogsFileView$: Observable<boolean> = this.appState.getParameter('isServiceLogsFileView');
+ get auditLogsCommonFieldNames() {
+ return auditLogsCommonFieldNames;
+ }
+
constructor(
private appState: AppStateService,
private tabsStorage: TabsService,
@@ -100,7 +106,6 @@ export class LogsContainerComponent implements OnInit, OnDestroy {
) {}
ngOnInit() {
- this.logsContainerService.loadColumnsNames();
// set te logsType when the activeLogsType state has changed
this.subscriptions.push(
this.appState.getParameter('activeLogsType').subscribe((value: LogsType) => this.logsType = value)
diff --git a/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts b/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts
index da33f60..231ddc5 100644
--- a/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts
+++ b/ambari-logsearch-web/src/app/components/search-box/search-box.component.ts
@@ -16,14 +16,13 @@
* limitations under the License.
*/
-import {Component, OnInit, OnDestroy, HostListener, Input, ViewChild, ElementRef, forwardRef} from '@angular/core';
-import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
-import {Subject} from 'rxjs/Subject';
-import {SearchBoxParameter, SearchBoxParameterProcessed, SearchBoxParameterTriggered} from '@app/classes/filtering';
-import {ListItem} from '@app/classes/list-item';
-import {HomogeneousObject} from '@app/classes/object';
-import {UtilsService} from '@app/services/utils.service';
-import {Subscription} from 'rxjs/Subscription';
+import { Component, OnInit, OnDestroy, HostListener, Input, ViewChild, ElementRef, forwardRef } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { Subject } from 'rxjs/Subject';
+import { SearchBoxParameter, SearchBoxParameterProcessed, SearchBoxParameterTriggered } from '@app/classes/filtering';
+import { ListItem } from '@app/classes/list-item';
+import { HomogeneousObject } from '@app/classes/object';
+import { UtilsService } from '@app/services/utils.service';
@Component({
selector: 'search-box',
@@ -39,21 +38,21 @@ import {Subscription} from 'rxjs/Subscription';
})
export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccessor {
- private currentId: number = 0;
+ private currentId = 0;
- private isExclude: boolean = false;
+ private isExclude = false;
/**
* Indicates whether search box is currently active
* @type {boolean}
*/
- isActive: boolean = false;
+ isActive = false;
/**
* Indicates whether search query parameter value is currently typed
* @type {boolean}
*/
- isValueInput: boolean = false;
+ isValueInput = false;
currentValue: string;
@@ -61,13 +60,13 @@ export class SearchBoxComponent implements OnInit, OnDestroy, ControlValueAccess
* Indicates whether there's no autocomplete matches in preset options for search query parameter name
* @type {boolean}
*/
- private noMatchingParameterName: boolean = true;
+ private noMatchingParameterName = true;
/**
* Indicates whether there's no autocomplete matches in preset options for search query parameter value
* @type {boolean}
*/
- private noMatchingParameterValue: boolean = true;
+ private noMatchingParameterValue = true;
@Input()
items: ListItem[] = [];
diff --git a/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts b/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
index bfb6068..44f452f 100644
--- a/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
+++ b/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
@@ -25,7 +25,8 @@ import {
ElementRef,
Input,
ChangeDetectorRef,
- SimpleChanges
+ SimpleChanges,
+ OnChanges
} from '@angular/core';
import { Subject } from 'rxjs/Subject';
@@ -50,7 +51,7 @@ export enum ListLayout {
templateUrl: './service-logs-table.component.html',
styleUrls: ['./service-logs-table.component.less']
})
-export class ServiceLogsTableComponent extends LogsTableComponent implements AfterViewChecked, OnInit, OnDestroy {
+export class ServiceLogsTableComponent extends LogsTableComponent implements AfterViewChecked, OnInit, OnDestroy, OnChanges {
/**
* Extra css class which can be applied to the container element
@@ -183,7 +184,6 @@ export class ServiceLogsTableComponent extends LogsTableComponent implements Aft
ngOnChanges(changes: SimpleChanges) {
if (changes.hasOwnProperty('columns')) {
- this.displayedColumns = this.columns.filter((column: ListItem): boolean => column.isChecked);
this.tableRefresh$.next(Date.now());
}
}
diff --git a/ambari-logsearch-web/src/app/components/time-line-graph/time-line-graph.component.ts b/ambari-logsearch-web/src/app/components/time-line-graph/time-line-graph.component.ts
index 2f0b450..c9758a7 100644
--- a/ambari-logsearch-web/src/app/components/time-line-graph/time-line-graph.component.ts
+++ b/ambari-logsearch-web/src/app/components/time-line-graph/time-line-graph.component.ts
@@ -16,10 +16,10 @@
* limitations under the License.
*/
-import {Component, Input} from '@angular/core';
+import { Component, Input } from '@angular/core';
import * as d3 from 'd3';
-import {GraphScaleItem, GraphLinePoint, GraphLineData} from '@app/classes/graph';
-import {TimeGraphComponent} from '@app/classes/components/graph/time-graph.component';
+import { GraphScaleItem, GraphLinePoint, GraphLineData } from '@app/classes/graph';
+import { TimeGraphComponent } from '@app/classes/components/graph/time-graph.component';
@Component({
selector: 'time-line-graph',
@@ -32,13 +32,16 @@ import {TimeGraphComponent} from '@app/classes/components/graph/time-graph.compo
export class TimeLineGraphComponent extends TimeGraphComponent {
@Input()
- pointRadius: number = 3.5;
+ pointRadius = 3.5;
protected populate(): void {
- const keys = Object.keys(this.colors),
- data = this.data,
- timeStamps = Object.keys(data),
- dataForDomain = timeStamps.map((timeStamp: string): GraphScaleItem => Object.assign({
+ const data = this.data;
+ const keys = Object.keys(data).reduce((currentKeys, timeStamp): string[] => {
+ const dataKeys: string[] = Object.keys(data[timeStamp]).filter((key: string) => currentKeys.indexOf(key) === -1);
+ return [...currentKeys, ...dataKeys];
+ }, []);
+ const timeStamps = Object.keys(data);
+ const dataForDomain = timeStamps.map((timeStamp: string): GraphScaleItem => Object.assign({
tick: Number(timeStamp)
}, data[timeStamp])),
dataForSvg = keys.map((key: string): GraphLineData => {
@@ -51,8 +54,8 @@ export class TimeLineGraphComponent extends TimeGraphComponent {
}),
key: key
};
- }),
- line = d3.line<GraphScaleItem>().x(item => this.xScale(item.tick)).y(item => this.yScale(item.y));
+ });
+ const line = d3.line<GraphScaleItem>().x(item => this.xScale(item.tick)).y(item => this.yScale(item.y));
// after we have the data we set the domain values both scales
this.setXScaleDomain(dataForDomain);
diff --git a/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts b/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts
index cc107af..44d22be 100644
--- a/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts
+++ b/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts
@@ -26,7 +26,7 @@ import { HttpClientService } from 'app/services/http-client.service';
import { ClustersService } from 'app/services/storage/clusters.service';
import { ServiceLogsFieldsService } from 'app/services/storage/service-logs-fields.service';
import { AuditLogsFieldsService } from 'app/services/storage/audit-logs-fields.service';
-import { AuditFieldsDefinitionSet, LogField } from 'app/classes/object';
+import { AuditLogsFieldSet, LogField } from 'app/classes/object';
import { Observable } from 'rxjs/Observable';
import { HostsService } from 'app/services/storage/hosts.service';
import { NodeItem } from 'app/classes/models/node-item';
@@ -38,6 +38,7 @@ import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-a
import { Store } from '@ngrx/store';
import { AppStore } from '@app/classes/models/store';
import { isAuthorizedSelector } from '@app/store/selectors/auth.selectors';
+import { LoadAuditLogsReposAction } from '@app/store/actions/audit-log-repos.actions';
// @ToDo create a separate data state enrty in the store with keys of the model names
export enum DataStateStoreKeys {
@@ -51,7 +52,8 @@ export enum DataStateStoreKeys {
export const baseDataKeys: DataStateStoreKeys[] = [
DataStateStoreKeys.CLUSTERS_DATA_KEY,
DataStateStoreKeys.HOSTS_DATA_KEY,
- DataStateStoreKeys.COMPONENTS_DATA_KEY
+ DataStateStoreKeys.COMPONENTS_DATA_KEY,
+ DataStateStoreKeys.LOG_FIELDS_DATA_KEY
];
@Injectable()
@@ -77,15 +79,19 @@ export class AppLoadService {
Observable.combineLatest(
this.appStateService.getParameter(DataStateStoreKeys.CLUSTERS_DATA_KEY),
this.appStateService.getParameter(DataStateStoreKeys.COMPONENTS_DATA_KEY),
- this.appStateService.getParameter(DataStateStoreKeys.HOSTS_DATA_KEY)
+ this.appStateService.getParameter(DataStateStoreKeys.HOSTS_DATA_KEY),
+ this.appStateService.getParameter(DataStateStoreKeys.LOG_FIELDS_DATA_KEY)
).subscribe(this.onDataAvailibilityChange);
this.baseDataAvailibilityState$ = this.dataAvaibilityStateStore.getAll()
.map((dataAvailabilityState: DataAvaibilityStatesModel): DataAvailabilityValues => {
+
const values: DataAvailabilityValues[] = Object.keys(dataAvailabilityState)
.filter((key: DataStateStoreKeys): boolean => baseDataKeys.indexOf(key) > -1)
.map((key): DataAvailabilityValues => dataAvailabilityState[key]);
+
let nextDataState: DataAvailabilityValues = DataAvailabilityValues.NOT_AVAILABLE;
+
if (values.indexOf(DataAvailabilityValues.ERROR) > -1) {
nextDataState = DataAvailabilityValues.ERROR;
} else if (values.indexOf(DataAvailabilityValues.LOADING) > -1) {
@@ -93,7 +99,9 @@ export class AppLoadService {
} else if ( values.filter((value: DataAvailabilityValues) => value !== DataAvailabilityValues.AVAILABLE).length === 0 ) {
nextDataState = DataAvailabilityValues.AVAILABLE;
}
+
return nextDataState;
+
});
this.baseDataAvailibilityState$.subscribe(this.onBaseDataAvailabilityChange);
}
@@ -168,7 +176,7 @@ export class AppLoadService {
this.hostStoreService.clear();
}
- loadComponents(): Observable<[{[key: string]: any}, {[key: string]: any}]> {
+ loadServiceLogsComponents(): Observable<[{[key: string]: any}, {[key: string]: any}]> {
this.setDataAvaibility(DataStateStoreKeys.COMPONENTS_DATA_KEY, DataAvailabilityValues.LOADING);
const responseComponentsData$: Observable<Response> = this.httpClient.get('components').first()
.filter((response: Response) => response.ok)
@@ -199,25 +207,30 @@ export class AppLoadService {
return responses$;
}
+ loadAuditLogsComponents() {
+ this.store.dispatch(new LoadAuditLogsReposAction());
+ }
+
clearComponents(): void {
this.componentsStorageService.clear();
}
- loadFieldsForLogs(): Observable<[LogField[], AuditFieldsDefinitionSet]> {
+ loadFieldsForLogs(): Observable<[LogField[], AuditLogsFieldSet]> {
+ this.setDataAvaibility(DataStateStoreKeys.LOG_FIELDS_DATA_KEY, DataAvailabilityValues.LOADING);
const serviceLogsFieldsResponse$: Observable<LogField[]> = this.httpClient.get('serviceLogsFields')
.filter((response: Response) => response.ok)
.map((response: Response) => {
return response.json();
});
- const auditLogsFieldsResponse$: Observable<AuditFieldsDefinitionSet> = this.httpClient.get('auditLogsFields')
+ const auditLogsFieldsResponse$: Observable<AuditLogsFieldSet> = this.httpClient.get('auditLogsFields')
.filter((response: Response) => response.ok)
.map((response: Response) => {
return response.json();
});
- const responses$: Observable<[LogField[], AuditFieldsDefinitionSet]> = Observable.combineLatest(
+ const responses$: Observable<[LogField[], AuditLogsFieldSet]> = Observable.combineLatest(
serviceLogsFieldsResponse$, auditLogsFieldsResponse$
);
- responses$.subscribe(([serviceLogsFieldsResponse, auditLogsFieldsResponse]: [LogField[], AuditFieldsDefinitionSet]) => {
+ responses$.subscribe(([serviceLogsFieldsResponse, auditLogsFieldsResponse]: [LogField[], AuditLogsFieldSet]) => {
this.serviceLogsFieldsService.addInstances(serviceLogsFieldsResponse);
this.auditLogsFieldsService.setParameters(auditLogsFieldsResponse);
this.setDataAvaibility(DataStateStoreKeys.LOG_FIELDS_DATA_KEY, DataAvailabilityValues.AVAILABLE);
@@ -229,7 +242,9 @@ export class AppLoadService {
if (isAuthorized) {
this.loadClusters();
this.loadHosts();
- this.loadComponents();
+ this.loadServiceLogsComponents();
+ this.loadAuditLogsComponents();
+ this.loadFieldsForLogs();
} else {
this.clearClusters();
this.clearHosts();
diff --git a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.html b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.html
index 095585b..52f97be 100644
--- a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.html
+++ b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.html
@@ -33,7 +33,7 @@
</span>
</button>
<ul data-component="dropdown-list" (selectedItemChange)="updateSelection($event)"
- [ngClass]="{'dropdown-menu': true, 'dropdown-menu-right': isRightAlign}"
+ [ngClass]="{'dropdown-menu': true, 'dropdown-menu-right': isRightAlign}" [closeOnSelection]="closeOnSelection"
[items]="options" [actionArguments]="listItemArguments" [isMultipleChoice]="isMultipleChoice"
- [useClearToDefaultSelection]="useClearToDefaultSelection"></ul>
+ [useClearToDefaultSelection]="useClearToDefaultSelection" [useLocalFilter]="useDropDownLocalFilter"></ul>
</div>
diff --git a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts
index d59b7fe..77ea8e1 100644
--- a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts
+++ b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-button/dropdown-button.component.ts
@@ -70,6 +70,12 @@ export class DropdownButtonComponent {
@Input()
showTotalSelection = false;
+ @Input()
+ useDropDownLocalFilter = false;
+
+ @Input()
+ closeOnSelection = true;
+
protected selectedItems: ListItem[] = [];
get selection(): ListItem[] {
diff --git a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.html b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.html
index 89a794b..6cea2a1 100644
--- a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.html
+++ b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.html
@@ -16,7 +16,7 @@
-->
<ng-template #listItem let-item let-isMultipleChoice="isMultipleChoice">
<li [class.divider]="item.isDivider" [class.filtered]="isFiltered(item)"
- [attr.role]="item.isDivider ? 'separator' : null" [ngClass]="(item.cssClass || '')">
+ [attr.role]="item.isDivider ? 'separator' : null" [ngClass]="(item.cssClass || '')" (click)="onItemClick($event)">
<ng-container *ngIf="!item.isDivider">
<span class="list-item-label" *ngIf="isMultipleChoice">
<input type="checkbox" [attr.id]="(instanceId) + '-' + (item.id || item.value)" [(ngModel)]="item.isChecked"
diff --git a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
index 14537b6..8be7e64 100644
--- a/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
+++ b/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
@@ -71,6 +71,9 @@ export class DropdownListComponent implements OnInit, OnChanges, AfterViewChecke
@Input()
filterStr = '';
+ @Input()
+ closeOnSelection = true;
+
@ViewChild('selectAll')
selectAllRef: ElementRef;
@@ -206,6 +209,8 @@ export class DropdownListComponent implements OnInit, OnChanges, AfterViewChecke
private clearFilter = (event: MouseEvent): void => {
this.filterRegExp = null;
this.filterStr = '';
+ event.stopPropagation();
+ event.preventDefault();
}
private renderAdditionalComponents(): void {
@@ -225,6 +230,12 @@ export class DropdownListComponent implements OnInit, OnChanges, AfterViewChecke
this.selectedItemChange.emit(item);
}
+ onItemClick(event: MouseEvent) {
+ if (!this.closeOnSelection) {
+ event.stopPropagation();
+ }
+ }
+
doItemsCheck() {
this.separateSelections();
}
diff --git a/ambari-logsearch-web/src/app/modules/shared/dashrows.less b/ambari-logsearch-web/src/app/modules/shared/dashrows.less
new file mode 100644
index 0000000..9051759
--- /dev/null
+++ b/ambari-logsearch-web/src/app/modules/shared/dashrows.less
@@ -0,0 +1,92 @@
+/**
+ * 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";
+@import "mixins";
+
+.dashrow-container {
+ .dashrow-row-wrapper {
+ display: flex;
+ margin: @dashrow-margin;
+ position: relative;
+ .dashrow-initial {
+ .hexagon(@dashrow-hexagon-size);
+ align-self: center;
+ color: @white;
+ left: -(@dashrow-hexagon-size/2);
+ order: -1;
+ position: absolute;
+ z-index: 2;
+ }
+ .dashrow-row {
+ align-items: stretch;
+ background-color: @white;
+ box-shadow: @dashrow-box-shadow;
+ display: flex;
+ flex: 1;
+ height: @dashrow-row-height;
+ overflow-x: auto;
+ overflow-y: hidden;
+ .dashrow-column-group {
+ align-items: stretch;
+ display: flex;
+ &[class*='dashrow-column-group-fixed-'] {
+ position: sticky;
+ }
+ &.dashrow-column-group-fixed-left {
+ background-color: @white;
+ box-shadow: @dashrow-fixed-group-side-box-shadow;
+ left: 0;
+ margin-right: 1rem;
+ padding: 0 2rem 0 5rem;
+ z-index: 1;
+ }
+ &.dashrow-column-group-fixed-right {
+ box-shadow: 1rem 0rem -1rem 1rem fadeout(@fluid-gray-2, .3);
+ margin-left: 1rem;
+ right: 0;
+ z-index: 1;
+ }
+ .dashrow-column {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ .dashrow-value {
+ color: @dashrow-value-font-color;
+ font-size: @dashrow-value-font-size;
+
+ }
+ .dashrow-label {
+ color: @dashrow-label-color;
+ display: block;
+ font-size: @dashrow-label-font-size;
+ font-weight: lighter;
+ text-transform: uppercase;
+ white-space: nowrap;
+ }
+ }
+ }
+ }
+ }
+ .dashrow-row:first-child {
+ margin-top: 0;
+ }
+ .dashrow-row:last-child {
+ margin-bottom: 0;
+ }
+}
diff --git a/ambari-logsearch-web/src/app/modules/shared/main.less b/ambari-logsearch-web/src/app/modules/shared/main.less
index d120138..6421ab1 100644
--- a/ambari-logsearch-web/src/app/modules/shared/main.less
+++ b/ambari-logsearch-web/src/app/modules/shared/main.less
@@ -20,3 +20,4 @@
@import "mixins";
@import "forms";
@import "animations";
+@import "dashrows";
diff --git a/ambari-logsearch-web/src/app/modules/shared/mixins.less b/ambari-logsearch-web/src/app/modules/shared/mixins.less
index 3fab21d..64eaa28 100644
--- a/ambari-logsearch-web/src/app/modules/shared/mixins.less
+++ b/ambari-logsearch-web/src/app/modules/shared/mixins.less
@@ -211,3 +211,32 @@
.caret-mixin(@caret-width; @direction: down; @color: @base-font-color; @position: before) {
.caret-style(@caret-width, @direction, @color);
}
+
+.hexagon(@size: 2em, @color: @green) {
+ width: @size;
+ height: @size*0.55;
+ background: @color;
+ position: relative;
+ &:before {
+ content: "";
+ position: absolute;
+ top: -@size*0.25;
+ left: 0;
+ width: 0;
+ height: 0;
+ border-left: @size/2 solid transparent;
+ border-right: @size/2 solid transparent;
+ border-bottom: @size/4 solid @color;
+ }
+ &:after {
+ content: "";
+ position: absolute;
+ bottom: -@size/4;
+ left: 0;
+ width: 0;
+ height: 0;
+ border-left: @size/2 solid transparent;
+ border-right: @size/2 solid transparent;
+ border-top: @size/4 solid @color;
+ }
+}
diff --git a/ambari-logsearch-web/src/app/modules/shared/variables.less b/ambari-logsearch-web/src/app/modules/shared/variables.less
index 1f7c9e3..1d7fc94 100644
--- a/ambari-logsearch-web/src/app/modules/shared/variables.less
+++ b/ambari-logsearch-web/src/app/modules/shared/variables.less
@@ -17,15 +17,21 @@
*/
// Variables
+
+@font-size-root: 10px;
+@font-size-base: 10px;
+
@blue: #1491C1;
@grey: #DDD;
-@white: rgba(255, 255, 255, 1);
+@white: #FFF;
@fluid-gray-1: #ccc;
@fluid-gray-2: #999;
@fluid-gray-3: #666;
@fluid-gray-4: #333;
+@green: #3FAE2A;
+
@base-font-color: #666;
@navbar-background-color: #323544;
@navbar-logo-background-color: #303d54;
@@ -107,3 +113,17 @@
@notification-title-font-size: 14px;
@notification-content-font-size: 12px;
@notification-background-color: #FFF;
+
+// (Audit) Log List
+@log-list-label-color: @fluid-gray-2;
+
+
+@dashrow-row-height: 9rem;
+@dashrow-margin: 2rem 0;
+@dashrow-box-shadow: 0 0 1rem fadeout(@fluid-gray-2, 85%);
+@dashrow-fixed-group-side-box-shadow: 0 0 1rem 0 fadeout(@fluid-gray-2, 50%);
+@dashrow-value-font-size: 2rem;
+@dashrow-value-font-color: @fluid-gray-4;
+@dashrow-label-color: @fluid-gray-3;
+@dashrow-label-font-size: 1.2rem;
+@dashrow-hexagon-size: 3.8rem;
diff --git a/ambari-logsearch-web/src/styles.less b/ambari-logsearch-web/src/app/pipes/audit-log-field-label.pipe.ts
similarity index 57%
copy from ambari-logsearch-web/src/styles.less
copy to ambari-logsearch-web/src/app/pipes/audit-log-field-label.pipe.ts
index e3ecbb7..ca957a6 100644
--- a/ambari-logsearch-web/src/styles.less
+++ b/ambari-logsearch-web/src/app/pipes/audit-log-field-label.pipe.ts
@@ -15,17 +15,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@import './app/modules/shared/main';
-body {
- background-color: @main-background-color;
-}
-.initial-color {
- color: initial;
-}
-/** Override Bootstrap rules **/
-.btn-link {
- &:hover, &:focus {
- text-decoration: none;
+import { Pipe, PipeTransform } from '@angular/core';
+import { AppStore } from '@app/classes/models/store';
+import { Observable } from 'rxjs/Observable';
+import { Store } from '@ngrx/store';
+import { createAuditLogsFieldLabelSelector } from '@app/store/selectors/audit-logs-fields.selectors';
+
+@Pipe({
+ name: 'auditLogFieldLabel'
+})
+export class AuditLogFieldLabelPipe implements PipeTransform {
+
+ constructor(private store: Store<AppStore>) {
}
+
+ transform(name: string, component?: string): Observable<string> {
+ return this.store.select(createAuditLogsFieldLabelSelector(name, component));
+ }
+
}
diff --git a/ambari-logsearch-web/src/styles.less b/ambari-logsearch-web/src/app/pipes/repo-label.ts
similarity index 59%
copy from ambari-logsearch-web/src/styles.less
copy to ambari-logsearch-web/src/app/pipes/repo-label.ts
index e3ecbb7..1873b73 100644
--- a/ambari-logsearch-web/src/styles.less
+++ b/ambari-logsearch-web/src/app/pipes/repo-label.ts
@@ -15,17 +15,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@import './app/modules/shared/main';
-body {
- background-color: @main-background-color;
-}
-.initial-color {
- color: initial;
-}
-/** Override Bootstrap rules **/
-.btn-link {
- &:hover, &:focus {
- text-decoration: none;
+import { Pipe, PipeTransform } from '@angular/core';
+import { AppStore } from '@app/classes/models/store';
+import { Observable } from 'rxjs/Observable';
+import { Store } from '@ngrx/store';
+import { createSelectAuditLogReposLabelByRepoName } from '@app/store/selectors/audit-log-repos.selectors';
+
+@Pipe({
+ name: 'repoLabel'
+})
+export class RepoLabelPipe implements PipeTransform {
+
+ constructor(private store: Store<AppStore>) {
}
+
+ transform(name: string): Observable<string> {
+ return this.store.select(createSelectAuditLogReposLabelByRepoName(name));
+ }
+
}
diff --git a/ambari-logsearch-web/src/app/services/http-client.service.ts b/ambari-logsearch-web/src/app/services/http-client.service.ts
index 4b2152c..5957cd4 100644
--- a/ambari-logsearch-web/src/app/services/http-client.service.ts
+++ b/ambari-logsearch-web/src/app/services/http-client.service.ts
@@ -52,6 +52,9 @@ export class HttpClientService extends Http {
url: 'audit/logs',
params: opts => new AuditLogsListQueryParams(opts)
},
+ auditLogsComponents: {
+ url: 'audit/logs/components'
+ },
auditLogsGraph: {
url: 'audit/logs/bargraph',
params: opts => new AuditLogsGraphQueryParams(opts)
diff --git a/ambari-logsearch-web/src/app/services/logs-container.service.ts b/ambari-logsearch-web/src/app/services/logs-container.service.ts
index 0612744..62b52c5 100644
--- a/ambari-logsearch-web/src/app/services/logs-container.service.ts
+++ b/ambari-logsearch-web/src/app/services/logs-container.service.ts
@@ -51,7 +51,7 @@ import { ListItem } from '@app/classes/list-item';
import { HomogeneousObject, LogLevelObject } from '@app/classes/object';
import { DataAvailabilityValues, LogsType, ScrollType } from '@app/classes/string';
import { LogTypeTab } from '@app/classes/models/log-type-tab';
-import { AuditFieldsDefinitionSet } from '@app/classes/object';
+import { AuditLogsFieldSet } from '@app/classes/object';
import { AuditLog } from '@app/classes/models/audit-log';
import { ServiceLog } from '@app/classes/models/service-log';
import { BarGraph } from '@app/classes/models/bar-graph';
@@ -70,6 +70,8 @@ import { AppStore } from '@app/classes/models/store';
import { isAuthorizedSelector } from '@app/store/selectors/auth.selectors';
import { Subscription } from 'rxjs/Subscription';
+import { AuditLogRepo } from '@app/store/reducers/audit-log-repos.reducers';
+import { selectAuditLogReposState } from '@app/store/selectors/audit-log-repos.selectors';
@Injectable()
export class LogsContainerService {
@@ -135,6 +137,13 @@ export class LogsContainerService {
defaultSelection: defaultFilterSelections.components,
fieldName: 'type'
},
+ repos: {
+ label: 'filter.repos',
+ iconClass: 'fa fa-cubes',
+ options: [],
+ defaultSelection: defaultFilterSelections.repos,
+ fieldName: 'repos'
+ },
levels: {
label: 'filter.levels',
iconClass: 'fa fa-sort-amount-asc',
@@ -226,6 +235,7 @@ export class LogsContainerService {
clusters: ['clusters'],
timeRange: ['to', 'from'],
components: ['mustBe'],
+ repos: ['mustBe'],
levels: ['level'],
hosts: ['hostList'],
auditLogsSorting: ['sortType', 'sortBy'],
@@ -256,7 +266,7 @@ export class LogsContainerService {
auditLogs: {
logsModel: this.auditLogsStorage,
fieldsModel: this.auditLogsFieldsStorage,
- listFilters: ['clusters', 'timeRange', 'auditLogsSorting', 'pageSize', 'page', 'query', 'users'],
+ listFilters: ['clusters', 'timeRange', 'repos', 'auditLogsSorting', 'pageSize', 'page', 'query', 'users'],
topResourcesFilters: ['clusters', 'timeRange', 'query'],
graphFilters: ['clusters', 'timeRange', 'query'],
graphRequestName: 'auditLogsGraph',
@@ -439,6 +449,9 @@ export class LogsContainerService {
});
this.clusterSelectionStoreService.getParameter(LogsContainerService.clusterSelectionStoreKey)
.filter(selection => !!selection).subscribe(this.onClusterSelectionChanged);
+
+ this.store.select(selectAuditLogReposState).subscribe(this.setAuditLogReposFilters);
+
}
//
@@ -759,21 +772,6 @@ export class LogsContainerService {
return graphData;
}
- loadColumnsNames(): void {
- this.httpClient.get('serviceLogsFields').subscribe((response: Response): void => {
- const jsonResponse = response.json();
- if (jsonResponse) {
- this.serviceLogsFieldsStorage.addInstances(jsonResponse);
- }
- });
- this.httpClient.get('auditLogsFields').subscribe((response: Response): void => {
- const jsonResponse: AuditFieldsDefinitionSet = response.json();
- if (jsonResponse) {
- this.auditLogsFieldsStorage.setParameters(jsonResponse);
- }
- });
- }
-
startCaptureTimer(): void {
this.startCaptureTime = new Date().valueOf();
const maxCaptureTimeInSeconds = this.maximumCaptureTimeLimit / 1000;
@@ -807,38 +805,6 @@ export class LogsContainerService {
this.captureSeconds = 0;
}
- loadClusters(): void {
-
- }
-
- loadComponents(): Observable<Response[]> {
- const requestComponentsData: Observable<Response> = this.httpClient.get('components');
- const requestComponentsName: Observable<Response> = this.httpClient.get('serviceComponentsName');
- const requests = Observable.combineLatest(requestComponentsName, requestComponentsData);
- requests.subscribe(([componentsNamesResponse, componentsDataResponse]: Response[]) => {
- const componentsNames = componentsNamesResponse.json();
- const componentsData = componentsDataResponse.json();
- const components = componentsData && componentsData.vNodeList.map((item): NodeItem => {
- const component = componentsNames.metadata.find(componentItem => componentItem.name === item.name);
- return Object.assign(item, {
- label: component && (component.label || item.name),
- group: component && component.group && {
- name: component.group,
- label: componentsNames.groups[component.group]
- },
- value: item.logLevelCount.reduce((currentValue: number, currentItem): number => {
- return currentValue + Number(currentItem.value);
- }, 0)
- });
- });
- if (components) {
- this.utils.pushUniqueValues(this.filters.components.options, components.map(node => this.utils.getListItemFromNode(node, true) ));
- this.componentsStorage.addInstances(components);
- }
- });
- return requests;
- }
-
setComponentsFilters = (components): void => {
this.filters.components.options = [];
if (components) {
@@ -849,6 +815,19 @@ export class LogsContainerService {
}
}
+ setAuditLogReposFilters = (items: AuditLogRepo[]): void => {
+ this.filters.repos.options = [];
+ if (items) {
+ this.utils.pushUniqueValues(
+ this.filters.repos.options,
+ items.map(item => ({
+ label: item.label,
+ value: item.name
+ }))
+ );
+ }
+ }
+
setClustersFilters = (clustersNames: string[]): void => {
this.filters.clusters.options = [];
if (clustersNames) {
diff --git a/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts b/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts
index d6bf06d..965681e 100644
--- a/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts
+++ b/ambari-logsearch-web/src/app/services/logs-filtering-utils.service.ts
@@ -49,6 +49,7 @@ export const defaultFilterSelections = {
label: 'filter.timeRange.1hr'
},
components: [],
+ repos: [],
levels: [],
hosts: [],
auditLogsSorting: {
diff --git a/ambari-logsearch-web/src/app/services/storage/reducers.service.ts b/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
index 4f72487..72ef28a 100644
--- a/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
+++ b/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
@@ -38,6 +38,7 @@ import {dataAvailabilityStates} from '@app/modules/app-load/stores/data-availabi
import * as auth from '@app/store/reducers/auth.reducers';
import * as filterHistory from '@app/store/reducers/filter-history.reducers';
+import * as auditLogRepos from '@app/store/reducers/audit-log-repos.reducers';
export const reducers = {
appSettings,
@@ -59,7 +60,8 @@ export const reducers = {
logsState,
dataAvailabilityStates,
auth: auth.reducer,
- filterHistory: filterHistory.reducer
+ filterHistory: filterHistory.reducer,
+ auditLogRepos: auditLogRepos.reducer
};
export function reducer(state: any, action: any) {
diff --git a/ambari-logsearch-web/src/app/store/actions/audit-log-repos.actions.ts b/ambari-logsearch-web/src/app/store/actions/audit-log-repos.actions.ts
new file mode 100644
index 0000000..b7f9bbe
--- /dev/null
+++ b/ambari-logsearch-web/src/app/store/actions/audit-log-repos.actions.ts
@@ -0,0 +1,52 @@
+/**
+ * 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 { Action } from '@ngrx/store';
+import { AuditLogRepo } from '../reducers/audit-log-repos.reducers';
+
+export enum AuditLogReposActionTypes {
+ LOAD = '[AuditLogRepos] Load',
+ LOADED = '[AuditLogRepos] Loaded',
+ SET = '[AuditLogRepos] Set',
+ CLEAR = '[AuditLogRepos] Clear'
+}
+
+export class LoadAuditLogsReposAction implements Action {
+ readonly type = AuditLogReposActionTypes.LOAD;
+ constructor() {}
+}
+
+export class LoadedAuditLogReposAction implements Action {
+ readonly type = AuditLogReposActionTypes.LOADED;
+ constructor(public payload: AuditLogRepo[]) {}
+}
+
+export class SetAuditLogReposAction implements Action {
+ readonly type = AuditLogReposActionTypes.SET;
+ constructor(public payload: AuditLogRepo[]) {}
+}
+
+export class ClearAuditLogReposAction implements Action {
+ readonly type = AuditLogReposActionTypes.CLEAR;
+ constructor() {}
+}
+
+export type AuditLogReposActions = LoadAuditLogsReposAction
+ | LoadedAuditLogReposAction
+ | SetAuditLogReposAction
+ | ClearAuditLogReposAction;
diff --git a/ambari-logsearch-web/src/app/store/effects/audit-log-repos.effects.ts b/ambari-logsearch-web/src/app/store/effects/audit-log-repos.effects.ts
new file mode 100644
index 0000000..ef94215
--- /dev/null
+++ b/ambari-logsearch-web/src/app/store/effects/audit-log-repos.effects.ts
@@ -0,0 +1,59 @@
+/**
+ * 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 { Injectable } from '@angular/core';
+import { Actions, Effect } from '@ngrx/effects';
+import { Observable } from 'rxjs/Observable';
+import { Response } from '@angular/http';
+
+import { AuditLogReposActionTypes, SetAuditLogReposAction } from '../actions/audit-log-repos.actions';
+import { HttpClientService } from '@app/services/http-client.service';
+import { AuditLogRepo } from '../reducers/audit-log-repos.reducers';
+
+@Injectable()
+export class AuditLogReposEffects {
+
+ @Effect()
+ LoadAuditLogRepos: Observable<any> = this.actions$
+ .ofType(AuditLogReposActionTypes.LOAD)
+ .switchMap((): Observable<SetAuditLogReposAction> => {
+ return this.httpClientService.get('auditLogsComponents')
+ .map((response: Response): SetAuditLogReposAction => {
+ const result = response.json();
+ const components: AuditLogRepo[] = Object.keys(result).reduce(
+ (auditLogsComponents: AuditLogRepo[], componentName: string): AuditLogRepo[] => {
+ return [
+ ...auditLogsComponents,
+ {
+ name: componentName,
+ label: result[componentName]
+ }
+ ];
+ },
+ []
+ );
+ return new SetAuditLogReposAction(components);
+ });
+ });
+
+ constructor(
+ private actions$: Actions,
+ private httpClientService: HttpClientService
+ ) {}
+
+}
diff --git a/ambari-logsearch-web/src/styles.less b/ambari-logsearch-web/src/app/store/reducers/audit-log-repos.reducers.ts
similarity index 62%
copy from ambari-logsearch-web/src/styles.less
copy to ambari-logsearch-web/src/app/store/reducers/audit-log-repos.reducers.ts
index e3ecbb7..c04ff3b 100644
--- a/ambari-logsearch-web/src/styles.less
+++ b/ambari-logsearch-web/src/app/store/reducers/audit-log-repos.reducers.ts
@@ -1,3 +1,5 @@
+import { AuditLogReposActions, AuditLogReposActionTypes } from "../actions/audit-log-repos.actions";
+
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -15,17 +17,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@import './app/modules/shared/main';
-body {
- background-color: @main-background-color;
-}
-.initial-color {
- color: initial;
-}
-/** Override Bootstrap rules **/
-.btn-link {
- &:hover, &:focus {
- text-decoration: none;
+export interface AuditLogRepo {
+ name: string;
+ label: string;
+};
+
+export const initialState = [];
+
+export function reducer(state = initialState, action: AuditLogReposActions) {
+ switch (action.type) {
+ case AuditLogReposActionTypes.SET: {
+ const components: AuditLogRepo[] = action.payload;
+ return components || [];
+ }
+ default: {
+ return state;
+ }
}
}
diff --git a/ambari-logsearch-web/src/app/classes/models/audit-log.ts b/ambari-logsearch-web/src/app/store/selectors/audit-log-repos.selectors.ts
similarity index 57%
copy from ambari-logsearch-web/src/app/classes/models/audit-log.ts
copy to ambari-logsearch-web/src/app/store/selectors/audit-log-repos.selectors.ts
index 380f14f..3643056 100644
--- a/ambari-logsearch-web/src/app/classes/models/audit-log.ts
+++ b/ambari-logsearch-web/src/app/store/selectors/audit-log-repos.selectors.ts
@@ -16,31 +16,18 @@
* limitations under the License.
*/
-import {Log} from '@app/classes/models/log';
+import { AppStore } from '@app/classes/models/store';
+import { AuditLogRepo } from '../reducers/audit-log-repos.reducers';
+import { createSelector } from 'reselect';
-export interface AuditLog extends Log {
- policy?: string;
- reason?: string;
- result: number;
- text?: string;
- tags?: string[];
- resource?: string;
- sess?: string;
- access?: string;
- logType: string;
- tags_str?: string;
- resType?: string;
- reqUser: string;
- reqData?: string;
- repoType: number;
- repo: string;
- proxyUsers?: string[];
- evtTime: number;
- enforcer: string;
- reqContext?: string;
- cliType?: string;
- cliIP?: string;
- agent?: string;
- agentHost?: string;
- action?: string;
+export const selectAuditLogReposState = (state: AppStore): AuditLogRepo[] => state.auditLogRepos;
+
+export function createSelectAuditLogReposLabelByRepoName(repoName: string) {
+ return createSelector(
+ selectAuditLogReposState,
+ (repos): string => {
+ const repoWithGivenName: AuditLogRepo = repos.find((repo: AuditLogRepo) => repo.name === repoName);
+ return repoWithGivenName ? repoWithGivenName.label : repoName;
+ }
+ );
}
diff --git a/ambari-logsearch-web/src/app/store/selectors/audit-logs-fields.selectors.ts b/ambari-logsearch-web/src/app/store/selectors/audit-logs-fields.selectors.ts
index 60eddcc..09a7c19 100644
--- a/ambari-logsearch-web/src/app/store/selectors/audit-logs-fields.selectors.ts
+++ b/ambari-logsearch-web/src/app/store/selectors/audit-logs-fields.selectors.ts
@@ -18,32 +18,31 @@
import { createSelector, Selector } from 'reselect';
import { AppStore } from '@app/classes/models/store';
-import { LogField } from '@app/classes/object';
+import { LogField, AuditLogsFieldSet, AuditLogsFieldsSetRootKeys } from '@app/classes/object';
import { ResponseRootProperties } from '@app/services/storage/audit-logs-fields.service';
-export const selectAuditLogsFieldState = (state: AppStore): LogField[] => state.auditLogsFields;
+export const selectAuditLogsFieldState = (state: AppStore): AuditLogsFieldSet => state.auditLogsFields;
export const selectDefaultAuditLogsFields = createSelector(
selectAuditLogsFieldState,
- (root) => root && root[ResponseRootProperties.DEFAULTS]
+ (root: AuditLogsFieldSet): LogField[] => root && <LogField[]>root[AuditLogsFieldsSetRootKeys.DEFAULTS]
);
-export const createAuditLogsFieldComponentFieldsSelectorByComponentName = (componentName: string): Selector<AppStore, LogField[]> => (
- createSelector(
+export const createAuditLogsFieldSetSelector = (componentName?: string) => {
+ return createSelector(
selectAuditLogsFieldState,
- (root): LogField[] => {
+ (root: AuditLogsFieldSet): LogField[] => {
const overrides = root[ResponseRootProperties.OVERRIDES];
- return (overrides && overrides[componentName]) || root[ResponseRootProperties.DEFAULTS];
+ return (componentName && overrides && overrides[componentName]) || root[ResponseRootProperties.DEFAULTS];
}
- )
-);
+ );
+}
-export const createAuditLogsFieldLabelSelectorByComponentNameAndFieldName = (
- componentName: string,
- fieldName: string
+export const createAuditLogsFieldLabelSelector = (
+ fieldName: string,
+ componentName?: string
): Selector<AppStore, string> => createSelector(
- selectAuditLogsFieldState,
- createAuditLogsFieldComponentFieldsSelectorByComponentName(componentName),
+ createAuditLogsFieldSetSelector(componentName),
(fields: LogField[]): string => {
const field: LogField = fields.find((nextField: LogField) => nextField.name === fieldName);
return field ? field.label : fieldName;
diff --git a/ambari-logsearch-web/src/assets/i18n/en.json b/ambari-logsearch-web/src/assets/i18n/en.json
index 0e60563..9433296 100644
--- a/ambari-logsearch-web/src/assets/i18n/en.json
+++ b/ambari-logsearch-web/src/assets/i18n/en.json
@@ -8,6 +8,7 @@
"common.value": "Value",
"common.settings": "Settings",
"common.loading": "Loading...",
+ "common.notAvailable": "N/A",
"common.form.errors.required": "This field is required",
@@ -47,6 +48,7 @@
"filter.clusters": "Clusters",
"filter.components": "Components",
+ "filter.repos": "Audit Source",
"filter.levels": "Levels",
"filter.include": "Include",
"filter.exclude": "Exclude",
@@ -237,8 +239,8 @@
"logs.policy": "Policy",
"logs.proxyUsers": "Proxy Users",
"logs.reason": "Reason",
- "logs.repo": "Repo",
- "logs.repoType": "Repo Type",
+ "logs.repo": "Audit Source",
+ "logs.repoType": "Audit Source Type",
"logs.reqCallerId": "Req Caller Id",
"logs.reqContext": "Req Context",
"logs.reqData": "Req Data",
@@ -359,8 +361,10 @@
"dataAvaibilityState.clustersDataState.label": "Loading clusters",
"dataAvaibilityState.hostsDataState.label": "Loading hosts",
"dataAvaibilityState.componentsDataState.label": "Loading components",
+ "dataAvaibilityState.logFieldsDataState.label": "Loading fields definitions",
"dataAvaibilityState.hasError.message": "We were not able to load the data. Please check your internet connection and reload the page!",
+
"urlParamsLabels": {
"clusters": "Clusters",
"timeRange": "Time range",
diff --git a/ambari-logsearch-web/src/styles.less b/ambari-logsearch-web/src/styles.less
index e3ecbb7..c3231c3 100644
--- a/ambari-logsearch-web/src/styles.less
+++ b/ambari-logsearch-web/src/styles.less
@@ -15,9 +15,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@import './app/modules/shared/main';
+@import './app/modules/shared/main';s
+html {
+ font-size: @font-size-base;
+}
body {
background-color: @main-background-color;
+ font-size: 1.4rem;
}
.initial-color {
color: initial;
diff --git a/ambari-logsearch-web/yarn.lock b/ambari-logsearch-web/yarn.lock
index 32e3a25..5451634 100644
--- a/ambari-logsearch-web/yarn.lock
+++ b/ambari-logsearch-web/yarn.lock
@@ -486,6 +486,15 @@ ajv@^5.0.0, ajv@^5.1.5:
json-schema-traverse "^0.3.0"
json-stable-stringify "^1.0.1"
+ajv@^6.5.5:
+ version "6.5.5"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.5.tgz#cf97cdade71c6399a92c6d6c4177381291b781a1"
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
@@ -744,10 +753,18 @@ aws-sign2@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+aws-sign2@~0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+
aws4@^1.2.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+aws4@^1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
+
babel-code-frame@^6.11.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -875,8 +892,8 @@ better-assert@~1.0.0:
callsite "1.0.0"
big.js@^3.1.3:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
binary-extensions@^1.0.0:
version "1.8.0"
@@ -1237,9 +1254,9 @@ clone@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
-clone@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb"
+clone@^2.1.1, clone@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
co@^4.6.0:
version "4.6.0"
@@ -1314,6 +1331,12 @@ combined-stream@^1.0.5, combined-stream@~1.0.5:
dependencies:
delayed-stream "~1.0.0"
+combined-stream@^1.0.6, combined-stream@~1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
+ dependencies:
+ delayed-stream "~1.0.0"
+
commander@2:
version "2.9.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
@@ -2502,6 +2525,10 @@ extend@3, extend@^3.0.0, extend@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
+extend@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+
extglob@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
@@ -2534,6 +2561,14 @@ fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
+fast-deep-equal@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
@@ -2670,6 +2705,14 @@ form-data@~2.1.1:
combined-stream "^1.0.5"
mime-types "^2.1.12"
+form-data@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.6"
+ mime-types "^2.1.12"
+
forwarded@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363"
@@ -2926,6 +2969,10 @@ har-schema@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+har-schema@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+
har-validator@~4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
@@ -2933,6 +2980,13 @@ har-validator@~4.2.1:
ajv "^4.9.1"
har-schema "^1.0.5"
+har-validator@~5.1.0:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
+ dependencies:
+ ajv "^6.5.5"
+ har-schema "^2.0.0"
+
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
@@ -3132,6 +3186,14 @@ http-signature@~1.1.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
+http-signature@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+ dependencies:
+ assert-plus "^1.0.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
https-browserify@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
@@ -3630,6 +3692,10 @@ json-schema-traverse@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
@@ -3809,6 +3875,14 @@ less-loader@^4.0.5:
loader-utils "^1.1.0"
pify "^2.3.0"
+less-loader@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e"
+ dependencies:
+ clone "^2.1.1"
+ loader-utils "^1.1.0"
+ pify "^3.0.0"
+
less@^2.7.2:
version "2.7.2"
resolved "https://registry.yarnpkg.com/less/-/less-2.7.2.tgz#368d6cc73e1fb03981183280918743c5dcf9b3df"
@@ -3822,6 +3896,21 @@ less@^2.7.2:
request "^2.72.0"
source-map "^0.5.3"
+less@^3.8.1:
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/less/-/less-3.8.1.tgz#f31758598ef5a1930dd4caefa9e4340641e71e1d"
+ dependencies:
+ clone "^2.1.2"
+ optionalDependencies:
+ errno "^0.1.1"
+ graceful-fs "^4.1.2"
+ image-size "~0.5.0"
+ mime "^1.4.1"
+ mkdirp "^0.5.0"
+ promise "^7.1.1"
+ request "^2.83.0"
+ source-map "~0.6.0"
+
license-webpack-plugin@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-1.0.0.tgz#9515229075bacce8ec420cadf99a54a5f78cc7df"
@@ -4085,6 +4174,10 @@ mime-db@~1.27.0:
version "1.27.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+mime-db@~1.37.0:
+ version "1.37.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8"
+
mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7:
version "2.1.15"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
@@ -4097,6 +4190,12 @@ mime-types@~2.1.16:
dependencies:
mime-db "~1.30.0"
+mime-types@~2.1.19:
+ version "2.1.21"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96"
+ dependencies:
+ mime-db "~1.37.0"
+
mime@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
@@ -4109,6 +4208,10 @@ mime@^1.2.11:
version "1.4.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.0.tgz#69e9e0db51d44f2a3b56e48b7817d7d137f1a343"
+mime@^1.4.1:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+
mimic-fn@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
@@ -4409,6 +4512,10 @@ oauth-sign@~0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+oauth-sign@~0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+
object-assign@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
@@ -4675,6 +4782,10 @@ performance-now@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+
phantomjs-prebuilt@^2.1.7:
version "2.1.15"
resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.15.tgz#20f86e82d3349c505917527745b7a411e08b3903"
@@ -5073,6 +5184,10 @@ pseudomap@^1.0.1, pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+psl@^1.1.24:
+ version "1.1.29"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
+
public-encrypt@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
@@ -5091,6 +5206,10 @@ punycode@^1.2.4, punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+
q@1.4.1, q@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
@@ -5111,6 +5230,10 @@ qs@6.5.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49"
+qs@~6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+
query-string@^4.1.0:
version "4.3.4"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
@@ -5396,6 +5519,31 @@ request@2, request@^2.72.0, request@^2.78.0, request@^2.79.0, request@^2.81.0, r
tunnel-agent "^0.6.0"
uuid "^3.0.0"
+request@^2.83.0:
+ version "2.88.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.0"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.4.3"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
@@ -5469,6 +5617,10 @@ safe-buffer@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+safe-buffer@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+
sass-graph@^2.1.1:
version "2.2.4"
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
@@ -5792,6 +5944,10 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1:
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+source-map@~0.6.0:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+
spdx-correct@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
@@ -6100,6 +6256,13 @@ tough-cookie@~2.3.0:
dependencies:
punycode "^1.4.1"
+tough-cookie@~2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+ dependencies:
+ psl "^1.1.24"
+ punycode "^1.4.1"
+
trim-newlines@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
@@ -6300,6 +6463,12 @@ upper-case@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+uri-js@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ dependencies:
+ punycode "^2.1.0"
+
url-loader@^0.5.7:
version "0.5.9"
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.9.tgz#cc8fea82c7b906e7777019250869e569e995c295"
@@ -6375,6 +6544,10 @@ uuid@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+uuid@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
+
v8flags@^2.0.11:
version "2.1.1"
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"