You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by to...@apache.org on 2018/09/07 16:26:57 UTC
[ambari] branch branch-2.7 updated: [AMBARI-24580] [Log Search UI]
Change the fix with and the height for the modal to flexible layout (#2252)
This is an automated email from the ASF dual-hosted git repository.
tobiasistvan pushed a commit to branch branch-2.7
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/branch-2.7 by this push:
new 7a8e94d [AMBARI-24580] [Log Search UI] Change the fix with and the height for the modal to flexible layout (#2252)
7a8e94d is described below
commit 7a8e94d3f5b72abed96179472e0a0cb0d994f10d
Author: Istvan Tobias <to...@gmail.com>
AuthorDate: Fri Sep 7 18:26:54 2018 +0200
[AMBARI-24580] [Log Search UI] Change the fix with and the height for the modal to flexible layout (#2252)
* [AMBARI-24580] [Log Search UI] Change the fix with and the height for the modal to flexible layout
(cherry picked from commit 0ecf8a92c334da76fdfa03a138cc0cb30866393c)
* [AMBARI-24580] [Log Search UI] Change the fix width and the height for the modal to flexible layout - adding the missing licenses to the new files
(cherry picked from commit f76102bc252a2aa095ccccb91f221c4f2b57c2a3)
* [AMBARI-24580] [Log Search UI] Change the fix width and the height for the modal to flexible layout
(cherry picked from commit 7fed176701cdcdfda60d466dcf17eec082999377)
---
.../action-menu/action-menu.component.html | 29 +++--
.../action-menu/action-menu.component.less | 16 +++
.../action-menu/action-menu.component.spec.ts | 18 ++-
.../action-menu/action-menu.component.ts | 85 +++++++++++---
.../cluster-filter.component.spec.ts | 5 +-
.../cluster-filter/cluster-filter.component.ts | 2 +-
.../graph-legend-item.component.html | 2 +-
.../log-index-filter.component.html | 130 +++++++++++----------
.../log-index-filter.component.less | 79 ++++++++-----
.../log-index-filter.component.spec.ts | 10 +-
.../log-index-filter/log-index-filter.component.ts | 62 +++++++---
.../logs-container/logs-container.component.ts | 2 +-
.../timezone-picker.component.spec.ts | 8 +-
.../src/app/modules/app-load/app-load.module.ts | 2 +-
.../modules/app-load/services/app-load.service.ts | 2 +-
...e.store.ts => data-availability-state.store.ts} | 0
.../data-loading-indicator.component.html | 4 +-
.../data-loading-indicator.component.spec.ts | 8 +-
.../data-loading-indicator.component.ts | 2 +-
.../dropdown-list/dropdown-list.component.ts | 4 +
.../loading-indicator.component.html} | 6 +-
.../loading-indicator.component.less | 32 +++++
.../loading-indicator.component.spec.ts | 42 +++++++
.../loading-indicator.component.ts | 29 +++++
.../modal-dialog/modal-dialog.component.html | 37 ++++++
.../modal-dialog/modal-dialog.component.less | 56 +++++++++
.../modal-dialog/modal-dialog.component.spec.ts | 50 ++++++++
.../modal-dialog/modal-dialog.component.ts | 92 +++++++++++++++
.../src/app/modules/shared/shared.module.ts | 10 +-
.../app/services/log-index-filter.service.spec.ts | 45 +++++++
.../src/app/services/log-index-filter.service.ts | 40 +++++++
.../src/app/services/storage/reducers.service.ts | 2 +-
.../src/app/services/user-settings.service.spec.ts | 8 +-
.../src/app/services/user-settings.service.ts | 39 ++++---
34 files changed, 776 insertions(+), 182 deletions(-)
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html
index 3df719a..8970316 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.html
@@ -35,13 +35,26 @@
(buttonClick)="stopCapture()"></menu-button>
<menu-button label="{{'topMenu.refresh' | translate}}" iconClass="fa fa-refresh"
(buttonClick)="refresh()"></menu-button>
-<modal *ngIf="isLogIndexFilterDisplayed" (submit)="saveLogIndexFilter()" (cancel)="closeLogIndexFilter()"
- (close)="closeLogIndexFilter()" [isExtraLargeModal]="true" [isSubmitDisabled]="isModalSubmitDisabled"
- title="{{'logIndexFilter.title' | translate}}" submitButtonLabel="{{'modal.save' | translate}}">
- <ng-template>
+<modal-dialog
+ class="log-index-filter"
+ [visible]="isLogIndexFilterDisplayed$ | async"
+ [showCloseBtn]="false"
+ (onCloseRequest)="closeLogIndexFilter()"
+ title="{{'logIndexFilter.title' | translate}}">
+ <header>
+ <dropdown-button [options]="clustersListItems$ | async" (selectItem)="onSelectCluster($event)"
+ label="{{'logIndexFilter.selectCluster' | translate}}" buttonClass="btn-link"></dropdown-button>
+ </header>
+ <section>
+ <p>{{'logIndexFilter.caption' | translate}}</p>
<form [formGroup]="settingsForm">
- <log-index-filter formControlName="logIndexFilter"
- (changeIsSubmitDisabled)="setModalSubmitDisabled($event)"></log-index-filter>
+ <log-index-filter formControlName="logIndexFilter" (changeIsSubmitDisabled)="setModalSubmitDisabled($event)" [activeClusterName]="selectedClusterName$ | async"></log-index-filter>
</form>
- </ng-template>
-</modal>
+ </section>
+ <footer>
+ <button class="btn btn-secondary" (click)="closeLogIndexFilter()">{{'modal.cancel' | translate}}</button>
+ <button class="btn btn-primary" (click)="saveLogIndexFilter()" [disabled]="isModalSubmitDisabled">
+ {{'modal.save' | translate}}
+ </button>
+ </footer>
+</modal-dialog>
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less
index 090b544..c1f3014 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less
@@ -95,4 +95,20 @@
}
}
}
+ /deep/ .modal-body {
+ min-height: 25vh;
+ padding-top: 0;
+ }
+
+ /deep/ modal-dialog.log-index-filter .modal-header {
+ padding-top: 0;
+ padding-bottom: 15px;
+ header {
+ float: right;
+ }
+ dropdown-button button {
+ padding-left: 0;
+ padding-right: 0;
+ }
+ }
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
index 4ad7f44..4d84bb7 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.spec.ts
@@ -40,10 +40,12 @@ import {HistoryManagerService} from '@app/services/history-manager.service';
import {LogsContainerService} from '@app/services/logs-container.service';
import {UserSettingsService} from '@app/services/user-settings.service';
import {UtilsService} from '@app/services/utils.service';
-import {ModalComponent} from '@app/modules/shared/components/modal/modal.component';
+import {ModalDialogComponent} from '@app/modules/shared/components/modal-dialog/modal-dialog.component';
import {TimerSecondsPipe} from '@app/pipes/timer-seconds.pipe';
+import {ComponentLabelPipe} from '@app/pipes/component-label';
import {ActionMenuComponent} from './action-menu.component';
+import { LogIndexFilterComponent } from '@app/components/log-index-filter/log-index-filter.component';
import {ClusterSelectionService} from '@app/services/storage/cluster-selection.service';
import {RouterTestingModule} from '@angular/router/testing';
import {LogsStateService} from '@app/services/storage/logs-state.service';
@@ -52,6 +54,8 @@ import {LogsFilteringUtilsService} from '@app/services/logs-filtering-utils.serv
import {NotificationsService} from 'angular2-notifications/src/notifications.service';
import {NotificationService} from '@modules/shared/services/notification.service';
+import { DataAvailabilityStatesStore, dataAvailabilityStates } from '@app/modules/app-load/stores/data-availability-state.store';
+
describe('ActionMenuComponent', () => {
let component: ActionMenuComponent;
let fixture: ComponentFixture<ActionMenuComponent>;
@@ -76,13 +80,16 @@ describe('ActionMenuComponent', () => {
components,
hosts,
serviceLogsTruncated,
- tabs
+ tabs,
+ dataAvailabilityStates
})
],
declarations: [
+ LogIndexFilterComponent,
ActionMenuComponent,
- ModalComponent,
- TimerSecondsPipe
+ ModalDialogComponent,
+ TimerSecondsPipe,
+ ComponentLabelPipe
],
providers: [
...MockHttpRequestModules,
@@ -108,7 +115,8 @@ describe('ActionMenuComponent', () => {
LogsFilteringUtilsService,
LogsStateService,
NotificationsService,
- NotificationService
+ NotificationService,
+ DataAvailabilityStatesStore
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
index ad38711..fcf3587 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
@@ -16,32 +16,75 @@
* limitations under the License.
*/
-import {Component} from '@angular/core';
-import {FormGroup} from '@angular/forms';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {HistoryManagerService} from '@app/services/history-manager.service';
-import {UserSettingsService} from '@app/services/user-settings.service';
-import {ListItem} from '@app/classes/list-item';
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+
+import { Observable } from 'rxjs/Observable';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { Subscription } from 'rxjs/Subscription';
+
+import { LogsContainerService } from '@app/services/logs-container.service';
+import { HistoryManagerService } from '@app/services/history-manager.service';
+import { UserSettingsService } from '@app/services/user-settings.service';
+import { ListItem } from '@app/classes/list-item';
+import { ClustersService } from '@app/services/storage/clusters.service';
+import { UtilsService } from '@app/services/utils.service';
@Component({
selector: 'action-menu',
templateUrl: './action-menu.component.html',
styleUrls: ['./action-menu.component.less']
})
-export class ActionMenuComponent {
+export class ActionMenuComponent implements OnInit, OnDestroy {
- isLogIndexFilterDisplayed: boolean = false;
+ isLogIndexFilterDisplayed$: Observable<boolean> = this.route.queryParams
+ .map((params) => {
+ return params;
+ })
+ .map((params): boolean => /^(show|yes|true|1)$/.test(params.logIndexFilterSettings))
+ .distinctUntilChanged();
settingsForm: FormGroup = this.settings.settingsFormGroup;
- isModalSubmitDisabled: boolean = true;
+ isModalSubmitDisabled = true;
+
+ clustersListItems$: Observable<ListItem[]> = this.clustersService.getAll()
+ .map((clusterNames: string[]): ListItem[] => clusterNames.map(this.utilsService.getListItemFromString))
+ .map((clusters: ListItem[]) => {
+ if (clusters.length && !clusters.some((item: ListItem) => item.isChecked)) {
+ clusters[0].isChecked = true;
+ }
+ return clusters;
+ });
+
+ selectedClusterName$: BehaviorSubject<string> = new BehaviorSubject('');
+
+ subscriptions: Subscription[] = [];
constructor(
- private logsContainer: LogsContainerService, private historyManager: HistoryManagerService,
- private settings: UserSettingsService
+ private logsContainer: LogsContainerService,
+ private historyManager: HistoryManagerService,
+ private settings: UserSettingsService,
+ private route: ActivatedRoute,
+ private router: Router,
+ private clustersService: ClustersService,
+ private utilsService: UtilsService
) {
}
+ ngOnInit() {
+ this.subscriptions.push(
+ this.selectedClusterName$.subscribe(
+ (clusterName: string) => this.setModalSubmitDisabled(!(!!clusterName))
+ )
+ );
+ }
+
+ ngOnDestroy() {
+ this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
+ }
+
get undoItems(): ListItem[] {
return this.historyManager.undoItems;
}
@@ -86,16 +129,30 @@ export class ActionMenuComponent {
this.logsContainer.loadLogs();
}
+ onSelectCluster(cluster: string) {
+ this.selectedClusterName$.next(cluster);
+ }
+
openLogIndexFilter(): void {
- this.isLogIndexFilterDisplayed = true;
+ this.router.navigate(['.'], {
+ queryParamsHandling: 'merge',
+ queryParams: {logIndexFilterSettings: 'show'},
+ relativeTo: this.route.root.firstChild
+ });
}
closeLogIndexFilter(): void {
- this.isLogIndexFilterDisplayed = false;
+ this.route.queryParams.first().subscribe((queryParams) => {
+ const {logIndexFilterSettings, ...params} = queryParams;
+ this.router.navigate(['.'], {
+ queryParams: params,
+ relativeTo: this.route.root.firstChild
+ });
+ });
}
saveLogIndexFilter(): void {
- this.isLogIndexFilterDisplayed = false;
+ this.closeLogIndexFilter();
this.settings.saveIndexFilterConfig();
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.spec.ts
index 8a86923..8a6cbc6 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.spec.ts
@@ -50,7 +50,7 @@ import {LogsStateService} from '@app/services/storage/logs-state.service';
import {LogsFilteringUtilsService} from '@app/services/logs-filtering-utils.service';
import {NotificationService} from '@modules/shared/services/notification.service';
import {NotificationsService} from 'angular2-notifications/src/notifications.service';
-import { DataAvailabilityStatesStore } from '@modules/app-load/stores/data-avaibility-state.store';
+import { DataAvailabilityStatesStore, dataAvailabilityStates } from '@app/modules/app-load/stores/data-availability-state.store';
describe('ClusterFilterComponent', () => {
let component: ClusterFilterComponent;
@@ -83,7 +83,8 @@ describe('ClusterFilterComponent', () => {
tabs,
clusters,
components,
- hosts
+ hosts,
+ dataAvailabilityStates
})
],
providers: [
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
index 366b764..9921d41 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/cluster-filter/cluster-filter.component.ts
@@ -28,7 +28,7 @@ import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {FilterDropdownComponent} from '@modules/shared/components/filter-dropdown/filter-dropdown.component';
import {RoutingUtilsService} from '@app/services/routing-utils.service';
import {DataAvailabilityValues} from '@app/classes/string';
-import { DataAvailabilityStatesStore } from '@modules/app-load/stores/data-avaibility-state.store';
+import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
import { DataStateStoreKeys } from '@app/modules/app-load/services/app-load.service';
@Component({
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/graph-legend-item/graph-legend-item.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/graph-legend-item/graph-legend-item.component.html
index e1ebb70..76cdd2f 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/graph-legend-item/graph-legend-item.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/graph-legend-item/graph-legend-item.component.html
@@ -16,4 +16,4 @@
-->
<span class="color" [style.background-color]="color"></span>
-{{label}}
+<span class="item-label">{{label}}</span>
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.html
index e4acd72..f5dc84b 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.html
@@ -14,69 +14,71 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<div>{{'logIndexFilter.caption' | translate}}</div>
-<h5>{{'logIndexFilter.selectCluster' | translate}}</h5>
-<dropdown-button [options]="clustersListItems | async" (selectItem)="setActiveCluster($event)"
- label="{{'logIndexFilter.select' | translate}}" buttonClass="btn-default"></dropdown-button>
-<table *ngIf="activeClusterName" class="table table-hover">
- <thead>
- <tr>
- <th class="component-column">{{'filter.components' | translate}}</th>
- <th *ngFor="let column of columns" class="checkbox-column">
- <input type="checkbox" attr.id="{{column.name}}"
- [attr.checked]="isAllComponentsCheckedForLevel(column.name) ? 'checked' : null"
- (change)="processAllComponentsForLevel(column.name, $event.target.checked)">
- <label attr.for="{{column.name}}">
- <graph-legend-item label="{{column.label | translate}}" color="{{column.color}}"></graph-legend-item>
- </label>
- </th>
- <th class="override-column">{{'logIndexFilter.override' | translate}}</th>
- </tr>
- </thead>
- <tbody>
- <ng-container *ngFor="let component of activeClusterConfigs">
+<div [class]="'log-index-filter-content ' + ((configsAvailabilityState$ | async) | lowercase)">
+ <div class="log-index-filter-body">
+ <table *ngIf="activeClusterName" class="table table-header">
<tr>
- <td class="component-column">
- <input type="checkbox" attr.id="{{component.name}}"
- [attr.checked]="isAllLevelsCheckedForComponent(component.name) ? 'checked' : null"
- (change)="processAllLevelsForComponent(component.name, $event.target.checked)">
- <label attr.for="{{component.name}}">{{component.label | componentLabel | async}}</label>
- </td>
- <td *ngFor="let levelName of levelNames" class="checkbox-column">
- <input type="checkbox" attr.id="{{getCheckBoxId(component.name, levelName)}}"
- [(ngModel)]="component[levelName].defaults" (change)="updateValue()">
- <label attr.for="{{getCheckBoxId(component.name, levelName)}}"> </label>
- </td>
- <td class="override-column">
- <!-- <span class="overrides-toggle">{{'logIndexFilter.addHosts' | translate}}</span> -->
- </td>
- </tr>
- <tr> <!--overrides row -->
- <td class="component-column">
- <input type="checkbox" attr.id="{{component.name}}_overrides"
- [attr.checked]="isAllLevelsCheckedForComponent(component.name, true) ? 'checked' : null"
- (change)="processAllLevelsForComponent(component.name, $event.target.checked, true)">
- <label attr.for="{{component.name}}_overrides"> </label>
- </td>
- <td *ngFor="let levelName of levelNames" class="checkbox-column">
- <input type="checkbox" attr.id="{{getCheckBoxId(component.name, levelName, true)}}"
- [(ngModel)]="component[levelName].overrides" (change)="updateValue()">
- <label attr.for="{{getCheckBoxId(component.name, levelName, true)}}"> </label>
- </td>
- <td class="override-column">
- <div class="col-md-12 row">
- <div class="col-md-6">
- <div class="text-uppercase">{{'logIndexFilter.hostname' | translate}}</div>
- <input type="text" class="form-control" [(ngModel)]="component.hosts" (change)="updateValue()">
- </div>
- <div class=" col-md-6">
- <div class="text-uppercase">{{'logIndexFilter.expiryDate' | translate}}</div>
- <date-picker [time]="component.expiryTime" (timeChange)="setExpiryTime($event, component)"></date-picker>
- </div>
- </div>
- </td>
+ <th class="component-column">{{'filter.components' | translate}}</th>
+ <th *ngFor="let column of columns" class="checkbox-column">
+ <input type="checkbox" attr.id="{{column.name}}"
+ [attr.checked]="isAllComponentsCheckedForLevel(column.name) ? 'checked' : null"
+ (change)="processAllComponentsForLevel(column.name, $event.target.checked)">
+ <label attr.for="{{column.name}}">
+ <graph-legend-item label="{{column.label | translate}}" color="{{column.color}}"></graph-legend-item>
+ </label>
+ </th>
+ <th class="override-column">{{'logIndexFilter.override' | translate}}</th>
</tr>
- </ng-container>
- </tbody>
-</table>
+ </table>
+ <div *ngIf="configsAreLoading$ | async" class="text-center">
+ <loading-indicator></loading-indicator>
+ </div>
+ <table *ngIf="activeClusterName" class="table">
+ <tbody>
+ <ng-container *ngFor="let component of (activeClusterConfigs$ | async)">
+ <tr class="component-default-row">
+ <td class="component-column">
+ <input type="checkbox" attr.id="{{component.name}}"
+ [attr.checked]="isAllLevelsCheckedForComponent(component.name) ? 'checked' : null"
+ (change)="processAllLevelsForComponent(component.name, $event.target.checked)">
+ <label attr.for="{{component.name}}">{{component.label | componentLabel | async}}</label>
+ </td>
+ <td *ngFor="let levelName of levelNames" class="checkbox-column">
+ <input type="checkbox" attr.id="{{getCheckBoxId(component.name, levelName)}}"
+ [(ngModel)]="component[levelName].defaults" (change)="updateValue()">
+ <label attr.for="{{getCheckBoxId(component.name, levelName)}}"> </label>
+ </td>
+ <td class="override-column">
+ <!-- <span class="overrides-toggle">{{'logIndexFilter.addHosts' | translate}}</span> -->
+ </td>
+ </tr>
+ <tr> <!--overrides row -->
+ <td class="component-column">
+ <input type="checkbox" attr.id="{{component.name}}_overrides"
+ [attr.checked]="isAllLevelsCheckedForComponent(component.name, true) ? 'checked' : null"
+ (change)="processAllLevelsForComponent(component.name, $event.target.checked, true)">
+ <label attr.for="{{component.name}}_overrides"> </label>
+ </td>
+ <td *ngFor="let levelName of levelNames" class="checkbox-column">
+ <input type="checkbox" attr.id="{{getCheckBoxId(component.name, levelName, true)}}"
+ [(ngModel)]="component[levelName].overrides" (change)="updateValue()">
+ <label attr.for="{{getCheckBoxId(component.name, levelName, true)}}"> </label>
+ </td>
+ <td class="override-column">
+ <div class="col-md-12 row">
+ <div class="col-md-6">
+ <div class="text-uppercase">{{'logIndexFilter.hostname' | translate}}</div>
+ <input type="text" class="form-control" [(ngModel)]="component.hosts" (change)="updateValue()">
+ </div>
+ <div class=" col-md-6">
+ <div class="text-uppercase">{{'logIndexFilter.expiryDate' | translate}}</div>
+ <date-picker [time]="component.expiryTime" (timeChange)="setExpiryTime($event, component)"></date-picker>
+ </div>
+ </div>
+ </td>
+ </tr>
+ </ng-container>
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
index 6b35474..a7f48bc 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
@@ -17,42 +17,59 @@
*/
@import '../../modules/shared/mixins';
+@import '../../modules/shared/variables';
+:host {
+ div.log-index-filter-content {
+ table {
+ &.table-header {
+ background-color: #fff;
+ margin-bottom: 0;
+ position: sticky;
+ top: -1px;
+ z-index: 10;
+ }
+ .component-column {
+ width: 25%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
-table {
- display: block;
- max-height: 70vh;
- overflow-y: auto;
- table-layout: fixed;
+ .checkbox-column {
+ width: 7%;
+ padding: 4px 0;
+ /deep/ graph-legend-item {
+ padding-right: 1px;
+ @media (max-width: 1510px) {
+ .item-label {
+ display: block;
+ }
+ }
+ }
+ }
- .component-column {
- width: auto;
- }
+ tr.component-default-row {
+ background-color: lighten(@grey-color, 10%);
+ }
- .checkbox-column {
- width: 100px;
- padding-left: 0;
- padding-right: 0;
+ .override-column {
+ width: 26%;
+ padding-right: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
- /deep/ graph-legend-item {
- padding-right: 1px;
- }
- }
+ th.override-column {
+ padding-left: 20px;
+ }
- .override-column {
- width: 32%;
- padding-right: 0;
- }
+ .overrides-toggle {
+ .clickable-item;
+ }
- th.override-column {
- padding-left: 20px;
- }
-
- .overrides-toggle {
- .clickable-item;
- }
-
- input[type=checkbox] + label {
- font-size: @table-font-size;
- top: 0;
+ input[type=checkbox] + label {
+ font-size: @table-font-size;
+ top: 0;
+ }
+ }
}
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.spec.ts
index b363d6f..3b042ae 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.spec.ts
@@ -51,7 +51,9 @@ import {LogsFilteringUtilsService} from '@app/services/logs-filtering-utils.serv
import {RouterTestingModule} from '@angular/router/testing';
import {NotificationsService} from 'angular2-notifications/src/notifications.service';
import {NotificationService} from '@modules/shared/services/notification.service';
-import {ComponentLabelPipe} from "@app/pipes/component-label";
+import {ComponentLabelPipe} from '@app/pipes/component-label';
+
+import { dataAvailabilityStates, DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
describe('LogIndexFilterComponent', () => {
let component: LogIndexFilterComponent;
@@ -76,7 +78,8 @@ describe('LogIndexFilterComponent', () => {
components,
hosts,
serviceLogsTruncated,
- tabs
+ tabs,
+ dataAvailabilityStates
})
],
declarations: [
@@ -109,7 +112,8 @@ describe('LogIndexFilterComponent', () => {
LogsFilteringUtilsService,
LogsStateService,
NotificationsService,
- NotificationService
+ NotificationService,
+ DataAvailabilityStatesStore
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
index 76443cd..65c22a4 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.ts
@@ -16,21 +16,24 @@
* limitations under the License.
*/
-import {Component, OnInit, Output, EventEmitter, forwardRef, OnDestroy} from '@angular/core';
-import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
-import {Observable} from 'rxjs/Observable';
+import { Component, OnInit, Input, Output, EventEmitter, forwardRef, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
-import {Subscription} from 'rxjs/Subscription';
-import {Moment} from 'moment';
-import {ListItem} from '@app/classes/list-item';
-import {HomogeneousObject, LogLevelObject} from '@app/classes/object';
-import {LogIndexFilterComponentConfig} from '@app/classes/settings';
-import {LogLevel} from '@app/classes/string';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {UserSettingsService} from '@app/services/user-settings.service';
-import {UtilsService} from '@app/services/utils.service';
-import {ClustersService} from '@app/services/storage/clusters.service';
-import {HostsService} from '@app/services/storage/hosts.service';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { Subscription } from 'rxjs/Subscription';
+import { Moment } from 'moment';
+import { ListItem } from '@app/classes/list-item';
+import { HomogeneousObject, LogLevelObject } from '@app/classes/object';
+import { LogIndexFilterComponentConfig } from '@app/classes/settings';
+import { LogLevel } from '@app/classes/string';
+import { LogsContainerService } from '@app/services/logs-container.service';
+import { UserSettingsService } from '@app/services/user-settings.service';
+import { UtilsService } from '@app/services/utils.service';
+import { ClustersService } from '@app/services/storage/clusters.service';
+import { HostsService } from '@app/services/storage/hosts.service';
+import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
+import { DataAvailabilityValues, DataAvailability } from '@app/classes/string';
@Component({
selector: 'log-index-filter',
@@ -44,7 +47,7 @@ import {HostsService} from '@app/services/storage/hosts.service';
}
]
})
-export class LogIndexFilterComponent implements OnInit, OnDestroy, ControlValueAccessor {
+export class LogIndexFilterComponent implements OnInit, OnDestroy, OnChanges, ControlValueAccessor {
@Output()
changeIsSubmitDisabled: EventEmitter<boolean> = new EventEmitter();
@@ -63,6 +66,12 @@ export class LogIndexFilterComponent implements OnInit, OnDestroy, ControlValueA
return clusterNames.map(this.utils.getListItemFromString);
});
+ configsAvailabilityState$: Observable<string> = this.dataAvailablilityStore.getParameter('logIndexFilter');
+ configsAreLoading$: Observable<boolean> = this.configsAvailabilityState$.distinctUntilChanged().map(
+ (state: DataAvailability) => state === DataAvailabilityValues.LOADING
+ );
+
+ @Input()
activeClusterName = '';
private subscriptions: Subscription[] = [];
@@ -72,9 +81,15 @@ export class LogIndexFilterComponent implements OnInit, OnDestroy, ControlValueA
*/
private configs: HomogeneousObject<LogIndexFilterComponentConfig[]>;
+ activeClusterConfigs$: BehaviorSubject<LogIndexFilterComponentConfig[]> = new BehaviorSubject(null);
+
constructor(
- private logsContainer: LogsContainerService, private settingsService: UserSettingsService,
- private utils: UtilsService, private clustersStorage: ClustersService, private hostsStorage: HostsService
+ private logsContainer: LogsContainerService,
+ private settingsService: UserSettingsService,
+ private utils: UtilsService,
+ private clustersStorage: ClustersService,
+ private hostsStorage: HostsService,
+ private dataAvailablilityStore: DataAvailabilityStatesStore
) {
}
@@ -89,12 +104,22 @@ export class LogIndexFilterComponent implements OnInit, OnDestroy, ControlValueA
this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
}
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.activeClusterName && this.configs) {
+ this.setCurrentConfig();
+ }
+ }
+
/**
* Configs for selected cluster
* @returns {LogIndexFilterComponentConfig[]}
*/
get activeClusterConfigs(): LogIndexFilterComponentConfig[] {
- return this.configs[this.activeClusterName];
+ return this.configs[this.activeClusterName] || [];
+ }
+
+ private setCurrentConfig() {
+ this.activeClusterConfigs$.next((this.configs && this.configs[this.activeClusterName]) || []);
}
/**
@@ -178,6 +203,7 @@ export class LogIndexFilterComponent implements OnInit, OnDestroy, ControlValueA
}
updateValue(): void {
+ this.setCurrentConfig();
if (this.onChange) {
this.onChange(this.configs);
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
index 1f4eba8..e8d2ee0 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
@@ -260,7 +260,7 @@ export class LogsContainerComponent implements OnInit, OnDestroy {
filters, this.logsContainerService.activeLogsType
);
this.paramsSyncStart(); // turn on the 'sync in progress' flag
- this.router.navigate([params], { relativeTo: this.activatedRoute})
+ this.router.navigate([params], { relativeTo: this.activatedRoute })
.then(this.paramsSyncStop, this.paramsSyncStop) // turn off the 'sync in progress' flag
.catch(this.paramsSyncStop); // turn off the 'sync in progress' flag
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
index b6bcaa2..736c7ef 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/timezone-picker/timezone-picker.component.spec.ts
@@ -52,6 +52,8 @@ import {LogsFilteringUtilsService} from '@app/services/logs-filtering-utils.serv
import {NotificationsService} from 'angular2-notifications/src/notifications.service';
import {NotificationService} from '@modules/shared/services/notification.service';
+import { dataAvailabilityStates, DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
+
describe('TimeZonePickerComponent', () => {
let component: TimeZonePickerComponent;
let fixture: ComponentFixture<TimeZonePickerComponent>;
@@ -78,7 +80,8 @@ describe('TimeZonePickerComponent', () => {
serviceLogsFields,
serviceLogsHistogramData,
serviceLogsTruncated,
- tabs
+ tabs,
+ dataAvailabilityStates
}),
...TranslationModules
],
@@ -106,7 +109,8 @@ describe('TimeZonePickerComponent', () => {
LogsFilteringUtilsService,
LogsStateService,
NotificationsService,
- NotificationService
+ NotificationService,
+ DataAvailabilityStatesStore
],
})
.compileComponents();
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/app-load.module.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/app-load.module.ts
index f062815..ade23da 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/app-load.module.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/app-load.module.ts
@@ -20,7 +20,7 @@ import { NgModule, APP_INITIALIZER } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppLoadService } from './services/app-load.service';
-import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-avaibility-state.store';
+import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
export function check_if_authorized(appLoadService: AppLoadService) {
return () => appLoadService.syncAuthorizedStateWithBackend();
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts
index 23fd4f9..9405c9b 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/services/app-load.service.ts
@@ -33,7 +33,7 @@ import {NodeItem} from 'app/classes/models/node-item';
import {ComponentsService} from 'app/services/storage/components.service';
import {DataAvailabilityValues} from 'app/classes/string';
import { DataAvaibilityStatesModel } from '@app/modules/app-load/models/data-availability-state.model';
-import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-avaibility-state.store';
+import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
// @ToDo create a separate data state enrty in the store with keys of the model names
export enum DataStateStoreKeys {
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/stores/data-avaibility-state.store.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/stores/data-availability-state.store.ts
similarity index 100%
rename from ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/stores/data-avaibility-state.store.ts
rename to ambari-logsearch/ambari-logsearch-web/src/app/modules/app-load/stores/data-availability-state.store.ts
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.html
index 780ca6a..b2441dd 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.html
@@ -26,9 +26,7 @@
<div class="label">{{ ('dataAvaibilityState.' + dataAvaibilityState.storeKey + '.label') | translate }}</div>
<div class="state-indicator">
<div *ngIf="dataAvaibilityState.avaibility === 'LOADING'" class="state state-loading">
- <svg class="circular-loader"viewBox="25 25 50 50" >
- <circle class="loading-path" cx="50" cy="50" r="20" fill="none" stroke-width="6" />
- </svg>
+ <loading-indicator></loading-indicator>
</div>
<div *ngIf="dataAvaibilityState.avaibility === 'AVAILABLE'" class="state state-available">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.2 130.2">
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.spec.ts
index 674e337..fdebdae 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.spec.ts
@@ -20,8 +20,9 @@ import {NO_ERRORS_SCHEMA} from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DataLoadingIndicatorComponent } from '@app/modules/shared/components/data-loading-indicator/data-loading-indicator.component';
import { TranslationModules } from '@app/test-config.spec';
-import { DataAvailabilityStatesStore, dataAvailabilityStates } from '@app/modules/app-load/stores/data-avaibility-state.store';
+import { DataAvailabilityStatesStore, dataAvailabilityStates } from '@app/modules/app-load/stores/data-availability-state.store';
import { StoreModule } from '@ngrx/store';
+import { LoadingIndicatorComponent } from '@app/modules/shared/components/loading-indicator/loading-indicator.component';
describe('DataLoadingIndicatorComponent', () => {
let component: DataLoadingIndicatorComponent;
@@ -35,7 +36,10 @@ describe('DataLoadingIndicatorComponent', () => {
dataAvailabilityStates
})
],
- declarations: [ DataLoadingIndicatorComponent ],
+ declarations: [
+ LoadingIndicatorComponent,
+ DataLoadingIndicatorComponent
+ ],
providers: [
DataAvailabilityStatesStore
]
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.ts
index 84410ae..e6800e1 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/data-loading-indicator/data-loading-indicator.component.ts
@@ -21,7 +21,7 @@ import { Subject } from 'rxjs/Subject';
import { DataStateStoreKeys, baseDataKeys } from '@app/modules/app-load/services/app-load.service';
import { Observable } from 'rxjs/Observable';
import { DataAvailabilityValues } from '@app/classes/string';
-import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-avaibility-state.store';
+import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
export interface DataAvaibilityObject {
storeKey: DataStateStoreKeys;
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
index 10ee68c..651578a 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/dropdown-list/dropdown-list.component.ts
@@ -87,6 +87,10 @@ export class DropdownListComponent implements OnInit, OnChanges, AfterViewChecke
ngOnInit() {
this.separateSelections();
this.setDefaultSelection(this.items);
+ // trigger selection if any of the items has been checked
+ if (this.items.some((item: ListItem) => item.isChecked)) {
+ this.selectedItemChange.emit(this.items);
+ }
this.subscriptions.push(
this.selectedItemChange.subscribe(this.separateSelections)
);
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/graph-legend-item/graph-legend-item.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.html
similarity index 84%
copy from ambari-logsearch/ambari-logsearch-web/src/app/components/graph-legend-item/graph-legend-item.component.html
copy to ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.html
index e1ebb70..ada351c 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/graph-legend-item/graph-legend-item.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.html
@@ -14,6 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<span class="color" [style.background-color]="color"></span>
-{{label}}
+<svg class="circular-loader"viewBox="25 25 50 50" >
+ <circle class="loading-path" cx="50" cy="50" r="20" fill="none" stroke-width="6" />
+</svg>
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.less
new file mode 100644
index 0000000..f09c3d0
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.less
@@ -0,0 +1,32 @@
+/**
+ * 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 '../../main';
+
+.circular-loader {
+ animation: rotate 2s linear infinite;
+ height: 20px;
+ transform-origin: center center;
+ width: 20px;
+}
+.loading-path {
+ stroke: @form-success-color;
+ stroke-dasharray: 150,200;
+ stroke-dashoffset: -10;
+ -webkit-animation: dash-loading 1.5s ease-in-out infinite, color 6s ease-in-out infinite;
+ animation: dash-loading 1.5s ease-in-out infinite, color 6s ease-in-out infinite;
+ stroke-linecap: round;
+}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.spec.ts
new file mode 100644
index 0000000..4d59ba0
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.spec.ts
@@ -0,0 +1,42 @@
+/**
+ * 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 { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LoadingIndicatorComponent } from './loading-indicator.component';
+
+describe('LoadingIndicatorComponent', () => {
+ let component: LoadingIndicatorComponent;
+ let fixture: ComponentFixture<LoadingIndicatorComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ LoadingIndicatorComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LoadingIndicatorComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.ts
new file mode 100644
index 0000000..2a3ce67
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/loading-indicator/loading-indicator.component.ts
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'loading-indicator',
+ templateUrl: './loading-indicator.component.html',
+ styleUrls: ['./loading-indicator.component.less']
+})
+export class LoadingIndicatorComponent {
+
+ constructor() {}
+
+}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.html
new file mode 100644
index 0000000..a096b3b
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.html
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+<div [class]="(extraCssClass || '') + ' modal'" [class.show]="visible">
+ <div *ngIf="showBackdrop" class="modal-backdrop" (click)="onBackdropClick($event)"></div>
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div *ngIf="showHeader" class="modal-header" #header>
+ <h4 *ngIf="title" class="modal-title">{{title | translate}}</h4>
+ <ng-content select="header"></ng-content>
+ <button *ngIf="showCloseBtn" type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="onCloseBtnClick($event)">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <ng-content></ng-content>
+ </div>
+ <div *ngIf="showFooter" class="modal-footer" #footer>
+ <ng-content select="footer"></ng-content>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.less
new file mode 100644
index 0000000..10f5e1c
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.less
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+:host {
+ .modal-backdrop {
+ opacity: .5;
+ z-index: 1040;
+ }
+ .modal-dialog {
+ margin: 2.5rem auto;
+ max-width: 90vw;
+ width: auto;
+ z-index: 1045;
+ .modal-content {
+ display: flex;
+ flex-direction: column;
+ max-height: 90vh;
+ overflow: hidden;
+ padding: 1.42rem;
+ .modal-header {
+ display: block;
+ flex-shrink: 1;
+ line-height: 1.42rem;
+ position: relative;
+ &> * {
+ display: inline-block;
+ }
+ .close {
+ position: absolute;
+ top: 0;
+ right: 1em;
+ }
+ }
+ .modal-body {
+ flex: 1;
+ overflow: auto;
+ }
+ .modal-footer {
+ flex-shrink: 1;
+ }
+ }
+ }
+}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.spec.ts
new file mode 100644
index 0000000..19cd74d
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.spec.ts
@@ -0,0 +1,50 @@
+/**
+ * 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 { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import {
+ getCommonTestingBedConfiguration, MockHttpRequestModules,
+ TranslationModules
+} from '@app/test-config.spec';
+
+import { ModalDialogComponent } from './modal-dialog.component';
+
+describe('ModalDialogComponent', () => {
+ let component: ModalDialogComponent;
+ let fixture: ComponentFixture<ModalDialogComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule(getCommonTestingBedConfiguration({
+ imports: [
+ ...TranslationModules
+ ],
+ declarations: [ ModalDialogComponent ]
+ }))
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ModalDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.ts
new file mode 100644
index 0000000..21a4e7e
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.ts
@@ -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 {
+ Component,
+ AfterViewInit,
+ Input,
+ Output,
+ EventEmitter,
+ ViewChild,
+ ChangeDetectorRef,
+ ElementRef
+} from '@angular/core';
+
+@Component({
+ selector: 'modal-dialog',
+ templateUrl: './modal-dialog.component.html',
+ styleUrls: ['./modal-dialog.component.less']
+})
+export class ModalDialogComponent implements AfterViewInit {
+
+ @Input()
+ title: string;
+
+ @Input()
+ extraCssClass: string;
+
+ @Input()
+ showCloseBtn = true;
+
+ @Input()
+ showBackdrop = true;
+
+ @Input()
+ closeOnBackdropClick = true;
+
+ @Input()
+ visible = false;
+
+ @Output()
+ onCloseRequest: EventEmitter<MouseEvent> = new EventEmitter();
+
+ @ViewChild('header')
+ headerElementRef: ElementRef;
+
+ showHeader = true;
+
+ @ViewChild('footer')
+ footerElementRef: ElementRef;
+
+ showFooter = true;
+
+ constructor(private cdRef: ChangeDetectorRef) { }
+
+ ngAfterViewInit() {
+ let totalBuiltInHeaderElement = 0;
+ if (this.title) {
+ totalBuiltInHeaderElement += 1;
+ }
+ if (this.showCloseBtn) {
+ totalBuiltInHeaderElement += 1;
+ }
+ this.showHeader = this.headerElementRef && (this.headerElementRef.nativeElement.children.length - totalBuiltInHeaderElement > 0);
+ this.showFooter = this.footerElementRef && this.footerElementRef.nativeElement.children.length;
+ this.cdRef.detectChanges();
+ }
+
+ onCloseBtnClick(event: MouseEvent) {
+ this.onCloseRequest.emit(event);
+ }
+
+ onBackdropClick(event: MouseEvent) {
+ if (this.closeOnBackdropClick) {
+ this.onCloseRequest.emit(event);
+ }
+ }
+
+}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
index 6ab76a8..833ef85 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
@@ -38,6 +38,8 @@ import {DropdownListComponent} from './components/dropdown-list/dropdown-list.co
import {FilterDropdownComponent} from './components/filter-dropdown/filter-dropdown.component';
import {ModalComponent} from './components/modal/modal.component';
import { DataLoadingIndicatorComponent } from '@app/modules/shared/components/data-loading-indicator/data-loading-indicator.component';
+import { ModalDialogComponent } from './components/modal-dialog/modal-dialog.component';
+import { LoadingIndicatorComponent } from './components/loading-indicator/loading-indicator.component';
@NgModule({
imports: [
@@ -60,7 +62,9 @@ import { DataLoadingIndicatorComponent } from '@app/modules/shared/components/da
DropdownListComponent,
FilterDropdownComponent,
ModalComponent,
- DataLoadingIndicatorComponent
+ DataLoadingIndicatorComponent,
+ ModalDialogComponent,
+ LoadingIndicatorComponent
],
providers: [
Title,
@@ -74,7 +78,9 @@ import { DataLoadingIndicatorComponent } from '@app/modules/shared/components/da
DropdownListComponent,
FilterDropdownComponent,
ModalComponent,
- DataLoadingIndicatorComponent
+ DataLoadingIndicatorComponent,
+ ModalDialogComponent,
+ LoadingIndicatorComponent
]
})
export class SharedModule { }
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/log-index-filter.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/log-index-filter.service.spec.ts
new file mode 100644
index 0000000..924deee
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/log-index-filter.service.spec.ts
@@ -0,0 +1,45 @@
+/**
+ * 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 { TestBed, inject } from '@angular/core/testing';
+
+import {
+ getCommonTestingBedConfiguration,
+ TranslationModules
+} from '@app/test-config.spec';
+
+import { AppStateService } from '@app/services/storage/app-state.service';
+
+import { LogIndexFilterService } from './log-index-filter.service';
+
+describe('LogIndexFilterService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule(getCommonTestingBedConfiguration({
+ imports: [
+ ...TranslationModules
+ ],
+ providers: [
+ AppStateService,
+ LogIndexFilterService
+ ]
+ }));
+ });
+
+ it('should be created', inject([LogIndexFilterService], (service: LogIndexFilterService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/log-index-filter.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/log-index-filter.service.ts
new file mode 100644
index 0000000..8aa0523
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/log-index-filter.service.ts
@@ -0,0 +1,40 @@
+/**
+ * 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 {Response} from '@angular/http';
+
+import { Observable } from 'rxjs/Observable';
+
+import { HttpClientService } from '@app/services/http-client.service';
+import { Filter } from '@app/classes/models/filter';
+
+@Injectable()
+export class LogIndexFilterService {
+
+ constructor(private httpClient: HttpClientService) { }
+
+ getFilterByClusterName(clusterName: string): Observable<Filter> {
+ return this.httpClient.get('logIndexFilters', null, {
+ clusterName
+ }).map((response: Response): Filter => {
+ const filters: Filter = response.json() && response.json().filter;
+ return filters;
+ });
+ }
+
+}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
index 207f7e4..cd67461 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/storage/reducers.service.ts
@@ -34,7 +34,7 @@ import {userConfigs} from '@app/services/storage/user-configs.service';
import {tabs} from '@app/services/storage/tabs.service';
import {clusterSelections} from '@app/services/storage/cluster-selection.service';
import {logsState} from '@app/services/storage/logs-state.service';
-import {dataAvailabilityStates} from '@modules/app-load/stores/data-avaibility-state.store';
+import {dataAvailabilityStates} from '@app/modules/app-load/stores/data-availability-state.store';
export const reducers = {
appSettings,
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.spec.ts
index 7dcca94..8dce161 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.spec.ts
@@ -46,6 +46,8 @@ import {LogsStateService} from '@app/services/storage/logs-state.service';
import {NotificationsService} from 'angular2-notifications/src/notifications.service';
import {NotificationService} from '@modules/shared/services/notification.service';
+import { dataAvailabilityStates, DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
+
describe('UserSettingsService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
@@ -64,7 +66,8 @@ describe('UserSettingsService', () => {
components,
hosts,
serviceLogsTruncated,
- tabs
+ tabs,
+ dataAvailabilityStates
}),
...TranslationModules
],
@@ -91,7 +94,8 @@ describe('UserSettingsService', () => {
LogsFilteringUtilsService,
LogsStateService,
NotificationsService,
- NotificationService
+ NotificationService,
+ DataAvailabilityStatesStore
]
});
});
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.ts
index b972d6f..2b4de0a 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/user-settings.service.ts
@@ -16,19 +16,21 @@
* limitations under the License.
*/
-import {Injectable} from '@angular/core';
-import {FormGroup, FormControl} from '@angular/forms';
-import {Response} from '@angular/http';
-import {HomogeneousObject, LogLevelObject} from '@app/classes/object';
-import {LevelOverridesConfig, LogIndexFilterComponentConfig} from '@app/classes/settings';
-import {LogLevel} from '@app/classes/string';
-import {Filter} from '@app/classes/models/filter';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {HttpClientService} from '@app/services/http-client.service';
-import {UtilsService} from '@app/services/utils.service';
-import {AppSettingsService} from '@app/services/storage/app-settings.service';
-import {TranslateService} from '@ngx-translate/core';
-import {NotificationService} from '@modules/shared/services/notification.service';
+import { Injectable } from '@angular/core';
+import { FormGroup, FormControl } from '@angular/forms';
+import { Response } from '@angular/http';
+import { HomogeneousObject, LogLevelObject } from '@app/classes/object';
+import { LevelOverridesConfig, LogIndexFilterComponentConfig } from '@app/classes/settings';
+import { LogLevel } from '@app/classes/string';
+import { Filter } from '@app/classes/models/filter';
+import { LogsContainerService } from '@app/services/logs-container.service';
+import { HttpClientService } from '@app/services/http-client.service';
+import { UtilsService } from '@app/services/utils.service';
+import { AppSettingsService } from '@app/services/storage/app-settings.service';
+import { TranslateService } from '@ngx-translate/core';
+import { NotificationService } from '@modules/shared/services/notification.service';
+import { DataAvailabilityStatesStore } from '@app/modules/app-load/stores/data-availability-state.store';
+import { DataAvailabilityValues } from '@app/classes/string';
@Injectable()
export class UserSettingsService {
@@ -49,7 +51,10 @@ export class UserSettingsService {
private utils: UtilsService,
private settingsStorage: AppSettingsService,
private translateService: TranslateService,
- private notificationService: NotificationService) {
+ private notificationService: NotificationService,
+ private dataAvailablilityStore: DataAvailabilityStatesStore
+ ) {
+ this.dataAvailablilityStore.setParameter('logIndexFilter', DataAvailabilityValues.NOT_AVAILABLE);
settingsStorage.getParameter('logIndexFilters').subscribe((filters: HomogeneousObject<HomogeneousObject<Filter>>): void => {
const configs = this.parseLogIndexFilterObjects(filters);
this.settingsFormGroup.controls.logIndexFilter.setValue(configs);
@@ -57,9 +62,10 @@ export class UserSettingsService {
}
loadIndexFilterConfig(clusterNames: string[]): void {
- let processedRequests: number = 0;
+ let processedRequests = 0;
const allFilters: HomogeneousObject<Filter> = {};
const totalCount = clusterNames.length;
+ this.dataAvailablilityStore.setParameter('logIndexFilter', DataAvailabilityValues.LOADING);
clusterNames.forEach((clusterName: string): void => {
this.httpClient.get('logIndexFilters', null, {
clusterName
@@ -71,6 +77,7 @@ export class UserSettingsService {
});
if (++processedRequests === totalCount) {
this.settingsStorage.setParameter('logIndexFilters', allFilters);
+ this.dataAvailablilityStore.setParameter('logIndexFilter', DataAvailabilityValues.AVAILABLE);
this.currentValues.logIndexFilter = allFilters;
}
}
@@ -81,7 +88,7 @@ export class UserSettingsService {
handleLogIndexFilterUpdate = (response: Response, cluster?: string): void => {
const title: string = this.translateService.instant('logIndexFilter.update.title');
const resultStr: string = response instanceof Response && response.ok ? 'success' : 'failed';
- const data: {[key: string]: any} = response instanceof Response ? response.json() : {};
+ const data: {[key: string]: any} = response instanceof Response && response.text() ? response.json() : {};
const message: string = this.translateService.instant(`logIndexFilter.update.${resultStr}`, {
message: '',
cluster: cluster || '',