[AMBARI-25028] [Log Search UI] Populate `Component Name` in validator (#67)
* MBARI-23456. Add cloud mode documentation (#66)
* [AMBARI-25028] [Log Search UI] Populate `Component Name` in validator
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 52f97be..b24d15a 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
@@ -15,16 +15,18 @@
limitations under the License.
-->
-<div [ngClass]="{'dropup': isDropup, 'has-selection': hasSelection}">
- <button [ngClass]="['btn', 'dropdown-toggle', buttonClass]" data-toggle="dropdown">
+<div [ngClass]="{ dropup: isDropup, 'has-selection': hasSelection }">
+ <button [ngClass]="['btn', 'dropdown-toggle', buttonClass]" [class.disabled]="disabled" data-toggle="dropdown">
<span class="filter-label">
<span *ngIf="iconClass || label" [class.plain]="!isMultipleChoice && !hideCaret && showSelectedValue">
<span *ngIf="iconClass" [ngClass]="iconClass"></span>
- <span *ngIf="label && (!hasSelection || isMultipleChoice || showCommonLabelWithSelection)"
- [class.label-before-selection]="isSelectionDisplayable">
- {{label}}
+ <span
+ *ngIf="label && (!hasSelection || isMultipleChoice || showCommonLabelWithSelection)"
+ [class.label-before-selection]="isSelectionDisplayable"
+ >
+ {{ label }}
</span>
- <span *ngIf="showTotalSelection && totalSelection" class="total-selection badge">{{totalSelection}}</span>
+ <span *ngIf="showTotalSelection && totalSelection" class="total-selection badge">{{ totalSelection }}</span>
</span>
<span *ngIf="isSelectionDisplayable">
<span class="selected-item-label" *ngFor="let item of selectedItems">{{ item.label | translate }}</span>
@@ -32,8 +34,15 @@
<span *ngIf="!hideCaret" class="caret"></span>
</span>
</button>
- <ul data-component="dropdown-list" (selectedItemChange)="updateSelection($event)"
- [ngClass]="{'dropdown-menu': true, 'dropdown-menu-right': isRightAlign}" [closeOnSelection]="closeOnSelection"
- [items]="options" [actionArguments]="listItemArguments" [isMultipleChoice]="isMultipleChoice"
- [useClearToDefaultSelection]="useClearToDefaultSelection" [useLocalFilter]="useDropDownLocalFilter"></ul>
+ <ul
+ data-component="dropdown-list"
+ (selectedItemChange)="updateSelection($event)"
+ [ngClass]="{ 'dropdown-menu': true, 'dropdown-menu-right': isRightAlign }"
+ [closeOnSelection]="closeOnSelection"
+ [items]="options"
+ [actionArguments]="listItemArguments"
+ [isMultipleChoice]="isMultipleChoice"
+ [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 77ea8e1..fb8a981 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
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { ListItem } from '@app/classes/list-item';
import { UtilsService } from '@app/services/utils.service';
@@ -25,8 +25,7 @@
templateUrl: './dropdown-button.component.html',
styleUrls: ['./dropdown-button.component.less']
})
-export class DropdownButtonComponent {
-
+export class DropdownButtonComponent implements OnChanges {
@Input()
label?: string;
@@ -76,6 +75,9 @@
@Input()
closeOnSelection = true;
+ @Input()
+ disabled = false;
+
protected selectedItems: ListItem[] = [];
get selection(): ListItem[] {
@@ -83,15 +85,19 @@
}
set selection(items: ListItem[]) {
- this.selectedItems = <ListItem[]>(Array.isArray(items) ? items : (items || []));
+ this.selectedItems = <ListItem[]>(Array.isArray(items) ? items : items || []);
if (this.selectedItems.length > 1 && !this.isMultipleChoice) {
this.selectedItems = this.selectedItems.slice(0, 1);
}
if (this.isMultipleChoice && this.options) {
- this.options.forEach((option: ListItem): void => {
- const selectionItem = this.selectedItems.find((item: ListItem): boolean => this.utils.isEqual(item.value, option.value));
- option.isChecked = !!selectionItem;
- });
+ this.options.forEach(
+ (option: ListItem): void => {
+ const selectionItem = this.selectedItems.find(
+ (item: ListItem): boolean => this.utils.isEqual(item.value, option.value)
+ );
+ option.isChecked = !!selectionItem;
+ }
+ );
}
}
@@ -113,9 +119,22 @@
return this.showSelectedValue && !this.isMultipleChoice && this.hasSelection;
}
- constructor(
- protected utils: UtilsService
- ) {}
+ get value(): any {
+ const values = this.selectedItems && this.selectedItems.length && this.selectedItems.map(item => item.value);
+ return this.isMultipleChoice ? values : values[0];
+ }
+
+ constructor(protected utils: UtilsService) {}
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.options) {
+ this.hanldeOptionsChange();
+ }
+ }
+
+ hanldeOptionsChange() {
+ this.filterAndSetSelection();
+ }
clearSelection(silent: boolean = false) {
let hasChange = false;
@@ -128,14 +147,16 @@
}
}
- updateSelection(updates: ListItem | ListItem[], callOnChange: boolean = true): boolean {
+ updateSelection(updates: ListItem | ListItem[]): boolean {
let hasChange = false;
if (updates && (!Array.isArray(updates) || updates.length)) {
const items: ListItem[] = Array.isArray(updates) ? updates : [updates];
if (this.isMultipleChoice) {
items.forEach((item: ListItem) => {
if (this.options && this.options.length) {
- const itemToUpdate: ListItem = this.options.find((option: ListItem) => this.utils.isEqual(option.value, item.value));
+ const itemToUpdate: ListItem = this.options.find((option: ListItem) =>
+ this.utils.isEqual(option.value, item.value)
+ );
if (itemToUpdate) {
hasChange = hasChange || itemToUpdate.isChecked !== item.isChecked;
itemToUpdate.isChecked = item.isChecked;
@@ -151,15 +172,18 @@
});
}
} else {
- this.options.forEach((item: ListItem) => item.isChecked = false);
+ this.options.forEach((item: ListItem) => (item.isChecked = false));
}
- const checkedItems = this.options.filter((option: ListItem): boolean => option.isChecked);
- this.selection = checkedItems;
+ this.filterAndSetSelection();
if (hasChange) {
- const selectedValues = checkedItems.map((option: ListItem): any => option.value);
+ const selectedValues = this.selection.map((option: ListItem): any => option.value);
this.selectItem.emit(this.isMultipleChoice ? selectedValues : selectedValues.shift());
}
return hasChange;
}
+ protected filterAndSetSelection() {
+ const checkedItems = this.options.filter((option: ListItem): boolean => option.isChecked);
+ this.selection = checkedItems;
+ }
}
diff --git a/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.spec.ts b/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.spec.ts
index 4157333..a8aff3f 100644
--- a/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.spec.ts
+++ b/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.spec.ts
@@ -15,37 +15,41 @@
* limitations under the License.
*/
-import {NO_ERRORS_SCHEMA} from '@angular/core';
-import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-import {MockHttpRequestModules, TranslationModules} from '@app/test-config.spec';
-import {StoreModule} from '@ngrx/store';
-import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
-import {AppStateService, appState} from '@app/services/storage/app-state.service';
-import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
-import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
-import {AuditLogsGraphDataService, auditLogsGraphData} from '@app/services/storage/audit-logs-graph-data.service';
-import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
-import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
+import { NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { MockHttpRequestModules, TranslationModules } from '@app/test-config.spec';
+import { StoreModule } from '@ngrx/store';
+import { AppSettingsService, appSettings } from '@app/services/storage/app-settings.service';
+import { AppStateService, appState } from '@app/services/storage/app-state.service';
+import { AuditLogsService, auditLogs } from '@app/services/storage/audit-logs.service';
+import { AuditLogsFieldsService, auditLogsFields } from '@app/services/storage/audit-logs-fields.service';
+import { AuditLogsGraphDataService, auditLogsGraphData } from '@app/services/storage/audit-logs-graph-data.service';
+import { ServiceLogsService, serviceLogs } from '@app/services/storage/service-logs.service';
+import { ServiceLogsFieldsService, serviceLogsFields } from '@app/services/storage/service-logs-fields.service';
import {
- ServiceLogsHistogramDataService, serviceLogsHistogramData
+ ServiceLogsHistogramDataService,
+ serviceLogsHistogramData
} from '@app/services/storage/service-logs-histogram-data.service';
-import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
-import {TabsService, tabs} from '@app/services/storage/tabs.service';
-import {ClustersService, clusters} from '@app/services/storage/clusters.service';
-import {ComponentsService, components} from '@app/services/storage/components.service';
-import {HostsService, hosts} from '@app/services/storage/hosts.service';
-import {UtilsService} from '@app/services/utils.service';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {AuthService} from '@app/services/auth.service';
+import {
+ ServiceLogsTruncatedService,
+ serviceLogsTruncated
+} from '@app/services/storage/service-logs-truncated.service';
+import { TabsService, tabs } from '@app/services/storage/tabs.service';
+import { ClustersService, clusters } from '@app/services/storage/clusters.service';
+import { ComponentsService, components } from '@app/services/storage/components.service';
+import { HostsService, hosts } from '@app/services/storage/hosts.service';
+import { UtilsService } from '@app/services/utils.service';
+import { LogsContainerService } from '@app/services/logs-container.service';
+import { AuthService } from '@app/services/auth.service';
-import {FilterDropdownComponent} from './filter-dropdown.component';
-import {ClusterSelectionService} from '@app/services/storage/cluster-selection.service';
-import {LogsStateService} from '@app/services/storage/logs-state.service';
-import {RoutingUtilsService} from '@app/services/routing-utils.service';
-import {LogsFilteringUtilsService} from '@app/services/logs-filtering-utils.service';
-import {RouterTestingModule} from '@angular/router/testing';
-import {NotificationService} from '@modules/shared/services/notification.service';
-import {NotificationsService} from 'angular2-notifications/src/notifications.service';
+import { FilterDropdownComponent } from './filter-dropdown.component';
+import { ClusterSelectionService } from '@app/services/storage/cluster-selection.service';
+import { LogsStateService } from '@app/services/storage/logs-state.service';
+import { RoutingUtilsService } from '@app/services/routing-utils.service';
+import { LogsFilteringUtilsService } from '@app/services/logs-filtering-utils.service';
+import { RouterTestingModule } from '@angular/router/testing';
+import { NotificationService } from '@modules/shared/services/notification.service';
+import { NotificationsService } from 'angular2-notifications/src/notifications.service';
import * as auth from '@app/store/reducers/auth.reducers';
import { EffectsModule } from '@ngrx/effects';
@@ -77,8 +81,7 @@
const httpClient = {
get: () => {
return {
- subscribe: () => {
- }
+ subscribe: () => {}
};
}
};
@@ -136,9 +139,8 @@
NotificationsService,
NotificationService
],
- schemas: [NO_ERRORS_SCHEMA]
- })
- .compileComponents();
+ schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
+ }).compileComponents();
}));
beforeEach(() => {
@@ -150,5 +152,4 @@
it('should create component', () => {
expect(component).toBeTruthy();
});
-
});
diff --git a/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts b/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts
index b0c766e..2bcf4a2 100644
--- a/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts
+++ b/ambari-logsearch-web/src/app/modules/shared/components/filter-dropdown/filter-dropdown.component.ts
@@ -15,10 +15,10 @@
* limitations under the License.
*/
-import {Component, forwardRef} from '@angular/core';
-import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
-import {DropdownButtonComponent} from '@modules/shared/components/dropdown-button/dropdown-button.component';
-import {ListItem} from '@app/classes/list-item';
+import { Component, forwardRef, Input } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { DropdownButtonComponent } from '@modules/shared/components/dropdown-button/dropdown-button.component';
+import { ListItem } from '@app/classes/list-item';
@Component({
selector: 'filter-dropdown',
@@ -33,7 +33,6 @@
]
})
export class FilterDropdownComponent extends DropdownButtonComponent implements ControlValueAccessor {
-
private onChange;
private _onChange(value) {
@@ -42,6 +41,9 @@
}
}
+ @Input()
+ options: ListItem[] = [];
+
updateSelection(updates: ListItem | ListItem[], callOnChange: boolean = true): boolean {
const hasChange = super.updateSelection(updates);
if (hasChange && callOnChange) {
@@ -50,15 +52,18 @@
return hasChange;
}
+ hanldeOptionsChange() {
+ super.hanldeOptionsChange();
+ this._onChange(this.selection);
+ }
+
writeValue(items: ListItem[]) {
- this.selection = items ? (Array.isArray(items) ? items : [items] ) : [];
+ this.selection = items ? (Array.isArray(items) ? items : [items]) : [];
}
registerOnChange(callback: any): void {
this.onChange = callback;
}
- registerOnTouched() {
- }
-
+ registerOnTouched() {}
}
diff --git a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.spec.ts b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.spec.ts
index 0ec4f56..a8e2b1f 100644
--- a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.spec.ts
+++ b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.spec.ts
@@ -16,39 +16,45 @@
* limitations under the License.
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import {ShipperConfigurationComponent} from './shipper-configuration.component';
-import {StoreModule} from '@ngrx/store';
-import {auditLogs, AuditLogsService} from '@app/services/storage/audit-logs.service';
-import {serviceLogsTruncated, ServiceLogsTruncatedService} from '@app/services/storage/service-logs-truncated.service';
-import {components, ComponentsService} from '@app/services/storage/components.service';
-import {UtilsService} from '@app/services/utils.service';
-import {tabs, TabsService} from '@app/services/storage/tabs.service';
-import {serviceLogs, ServiceLogsService} from '@app/services/storage/service-logs.service';
-import {hosts, HostsService} from '@app/services/storage/hosts.service';
-import {MockHttpRequestModules, TranslationModules} from '@app/test-config.spec';
-import {ComponentGeneratorService} from '@app/services/component-generator.service';
-import {auditLogsGraphData, AuditLogsGraphDataService} from '@app/services/storage/audit-logs-graph-data.service';
-import {serviceLogsHistogramData, ServiceLogsHistogramDataService} from '@app/services/storage/service-logs-histogram-data.service';
-import {clusters, ClustersService} from '@app/services/storage/clusters.service';
-import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
-import {appSettings, AppSettingsService} from '@app/services/storage/app-settings.service';
-import {appState, AppStateService} from '@app/services/storage/app-state.service';
-import {ClusterSelectionService} from '@app/services/storage/cluster-selection.service';
-import {serviceLogsFields, ServiceLogsFieldsService} from '@app/services/storage/service-logs-fields.service';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {ShipperRoutingModule} from '@modules/shipper/shipper-routing.module';
-import {ShipperClusterServiceListComponent} from '@modules/shipper/components/shipper-cluster-service-list/shipper-cluster-service-list.component';
-import {ShipperServiceConfigurationFormComponent} from '@modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component';
-import {FormsModule, ReactiveFormsModule} from '@angular/forms';
-import {TypeaheadModule} from 'ngx-bootstrap';
-import {DisableControlDirective} from '@modules/shared/directives/disable-control.directive';
-import {ModalComponent} from '@modules/shared/components/modal/modal.component';
-import {RouterTestingModule} from '@angular/router/testing';
-import {ShipperClusterServiceListService} from '@modules/shipper/services/shipper-cluster-service-list.service';
-import {ShipperConfigurationService} from '@modules/shipper/services/shipper-configuration.service';
-import {NotificationService} from '@modules/shared/services/notification.service';
-import {NotificationsService} from 'angular2-notifications/src/notifications.service';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ShipperConfigurationComponent } from './shipper-configuration.component';
+import { StoreModule } from '@ngrx/store';
+import { auditLogs, AuditLogsService } from '@app/services/storage/audit-logs.service';
+import {
+ serviceLogsTruncated,
+ ServiceLogsTruncatedService
+} from '@app/services/storage/service-logs-truncated.service';
+import { components, ComponentsService } from '@app/services/storage/components.service';
+import { UtilsService } from '@app/services/utils.service';
+import { tabs, TabsService } from '@app/services/storage/tabs.service';
+import { serviceLogs, ServiceLogsService } from '@app/services/storage/service-logs.service';
+import { hosts, HostsService } from '@app/services/storage/hosts.service';
+import { MockHttpRequestModules, TranslationModules } from '@app/test-config.spec';
+import { ComponentGeneratorService } from '@app/services/component-generator.service';
+import { auditLogsGraphData, AuditLogsGraphDataService } from '@app/services/storage/audit-logs-graph-data.service';
+import {
+ serviceLogsHistogramData,
+ ServiceLogsHistogramDataService
+} from '@app/services/storage/service-logs-histogram-data.service';
+import { clusters, ClustersService } from '@app/services/storage/clusters.service';
+import { AuditLogsFieldsService, auditLogsFields } from '@app/services/storage/audit-logs-fields.service';
+import { appSettings, AppSettingsService } from '@app/services/storage/app-settings.service';
+import { appState, AppStateService } from '@app/services/storage/app-state.service';
+import { ClusterSelectionService } from '@app/services/storage/cluster-selection.service';
+import { serviceLogsFields, ServiceLogsFieldsService } from '@app/services/storage/service-logs-fields.service';
+import { LogsContainerService } from '@app/services/logs-container.service';
+import { ShipperRoutingModule } from '@modules/shipper/shipper-routing.module';
+import { ShipperClusterServiceListComponent } from '@modules/shipper/components/shipper-cluster-service-list/shipper-cluster-service-list.component';
+import { ShipperServiceConfigurationFormComponent } from '@modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { TypeaheadModule } from 'ngx-bootstrap';
+import { DisableControlDirective } from '@modules/shared/directives/disable-control.directive';
+import { ModalComponent } from '@modules/shared/components/modal/modal.component';
+import { RouterTestingModule } from '@angular/router/testing';
+import { ShipperClusterServiceListService } from '@modules/shipper/services/shipper-cluster-service-list.service';
+import { ShipperConfigurationService } from '@modules/shipper/services/shipper-configuration.service';
+import { NotificationService } from '@modules/shared/services/notification.service';
+import { NotificationsService } from 'angular2-notifications/src/notifications.service';
describe('ShipperConfigurationComponent', () => {
let component: ShipperConfigurationComponent;
@@ -110,9 +116,9 @@
ShipperServiceConfigurationFormComponent,
DisableControlDirective,
ModalComponent
- ]
- })
- .compileComponents();
+ ],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+ }).compileComponents();
}));
beforeEach(() => {
diff --git a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts
index d8fccbd..82ae869 100644
--- a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts
+++ b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-configuration/shipper-configuration.component.ts
@@ -15,25 +15,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
-import {ActivatedRoute, Router} from '@angular/router';
-import {Response} from '@angular/http';
-import {Observable} from 'rxjs/Observable';
+import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Response } from '@angular/http';
+import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/skipWhile';
-import {NotificationService, NotificationType} from '@modules/shared/services/notification.service';
-import {CanComponentDeactivate} from '@modules/shared/services/can-deactivate-guard.service';
+import { NotificationService, NotificationType } from '@modules/shared/services/notification.service';
+import { CanComponentDeactivate } from '@modules/shared/services/can-deactivate-guard.service';
-import {ShipperCluster} from '../../models/shipper-cluster.type';
-import {ShipperClusterService} from '../../models/shipper-cluster-service.type';
-import {ShipperConfigurationService} from '../../services/shipper-configuration.service';
-import {ShipperClusterServiceListService} from '../../services/shipper-cluster-service-list.service';
-import {
- ShipperServiceConfigurationFormComponent
-} from '@modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component';
-import {TranslateService} from '@ngx-translate/core';
-import {ClusterSelectionService} from '@app/services/storage/cluster-selection.service';
-import {Subscription} from 'rxjs/Subscription';
+import { ShipperCluster } from '../../models/shipper-cluster.type';
+import { ShipperClusterService } from '../../models/shipper-cluster-service.type';
+import { ShipperConfigurationService } from '../../services/shipper-configuration.service';
+import { ShipperClusterServiceListService } from '../../services/shipper-cluster-service-list.service';
+import { ShipperServiceConfigurationFormComponent } from '@modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component';
+import { TranslateService } from '@ngx-translate/core';
+import { ClusterSelectionService } from '@app/services/storage/cluster-selection.service';
+import { Subscription } from 'rxjs/Subscription';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { FormGroup } from '@angular/forms';
@@ -43,7 +41,6 @@
styleUrls: ['./shipper-configuration.component.less']
})
export class ShipperConfigurationComponent implements CanComponentDeactivate, OnInit, OnDestroy {
-
static clusterSelectionStoreKey = 'shipper';
@Input()
@@ -57,21 +54,25 @@
private clusterName$: Observable<ShipperClusterService> = this.activatedRoute.params.map(params => params.cluster);
private serviceName$: Observable<ShipperClusterService> = this.activatedRoute.params.map(params => params.service);
- private serviceNamesList$: Observable<ShipperClusterService[]> = this.clusterName$.switchMap((cluster: ShipperCluster) => {
- return cluster ? this.shipperClusterServiceListService.getServicesForCluster(cluster) : Observable.of(undefined);
- });
+ private serviceNamesList$: Observable<ShipperClusterService[]> = this.clusterName$.switchMap(
+ (cluster: ShipperCluster) => {
+ return cluster ? this.shipperClusterServiceListService.getServicesForCluster(cluster) : Observable.of(undefined);
+ }
+ );
- private configuration$: Observable<{[key: string]: any}> = Observable.combineLatest(
- this.clusterName$,
- this.serviceName$
- ).switchMap(([clusterName, serviceName]: [ShipperCluster, ShipperClusterService]) => {
- return clusterName && serviceName ?
- this.shipperConfigurationService.loadConfiguration(clusterName, serviceName) : Observable.of(undefined);
- });
+ private configuration$: Observable<{
+ [key: string]: any;
+ }> = Observable.combineLatest(this.clusterName$, this.serviceName$).switchMap(
+ ([clusterName, serviceName]: [ShipperCluster, ShipperClusterService]) => {
+ return clusterName && serviceName
+ ? this.shipperConfigurationService.loadConfiguration(clusterName, serviceName)
+ : Observable.of(undefined);
+ }
+ );
private subscriptions: Subscription[] = [];
- validationResponse: {[key: string]: any};
+ validationResponse: { [key: string]: any };
constructor(
private router: Router,
@@ -81,7 +82,7 @@
private notificationService: NotificationService,
private translate: TranslateService,
private clusterSelectionStoreService: ClusterSelectionService
- ) { }
+ ) {}
ngOnInit() {
this.subscriptions.push(
@@ -98,7 +99,8 @@
}
private getPathMapForClusterFirstService(cluster: ShipperCluster): Observable<string[]> {
- return this.shipperClusterServiceListService.getServicesForCluster(cluster)
+ return this.shipperClusterServiceListService
+ .getServicesForCluster(cluster)
.switchMap((serviceNamesList: ShipperClusterService[]) => {
return Observable.of(this.getRouterLink([cluster, serviceNamesList[0]]));
});
@@ -112,26 +114,42 @@
if (clusterName) {
this.clusterName$.first().subscribe((currentClusterName: ShipperCluster) => {
if (currentClusterName !== clusterName) {
- this.getPathMapForClusterFirstService(clusterName).first().subscribe((path: string[]) => this.router.navigate(path));
+ this.getPathMapForClusterFirstService(clusterName)
+ .first()
+ .subscribe((path: string[]) => this.router.navigate(path));
}
});
}
- }
+ };
private getRouterLink(path: string | string[]): string[] {
return [...this.routerPath, ...(Array.isArray(path) ? path : [path])];
}
- getResponseHandler(cmd: string, type: string, form?: FormGroup) {
- const msgVariables = form.getRawValue();
+ getResponseHandler(cmd: string, type: string, msgVariables: any = {}, form?: FormGroup) {
return (response: Response) => {
const result = response.json();
// @ToDo change the backend response status to some error code if the configuration is not valid and don't use the .message prop
- const resultType = response ? (response.ok && !result.errorMessage ? NotificationType.SUCCESS : NotificationType.ERROR) : type;
- const translateParams = {errorMessage: (result && result.message) || '', ...msgVariables, ...result};
+ const resultType = response
+ ? response.ok && !result.errorMessage
+ ? NotificationType.SUCCESS
+ : NotificationType.ERROR
+ : type;
+ const translateParams = {
+ errorMessage: (result && result.message) || '',
+ ...msgVariables,
+ ...result
+ };
const title = this.translate.instant(`shipperConfiguration.action.${cmd}.title`, translateParams);
- const message = this.translate.instant(`shipperConfiguration.action.${cmd}.${resultType}.message`, translateParams);
- this.notificationService.addNotification({type: resultType, title, message});
+ const message = this.translate.instant(
+ `shipperConfiguration.action.${cmd}.${resultType}.message`,
+ translateParams
+ );
+ this.notificationService.addNotification({
+ type: resultType,
+ title,
+ message
+ });
if (resultType !== NotificationType.ERROR) {
form.markAsPristine();
}
@@ -149,23 +167,24 @@
service: rawValue.serviceName,
configuration: JSON.parse(rawValue.configuration)
}).subscribe(
- this.getResponseHandler(cmd, NotificationType.SUCCESS, configurationForm),
- this.getResponseHandler(cmd, NotificationType.ERROR, configurationForm)
+ this.getResponseHandler(cmd, NotificationType.SUCCESS, rawValue, configurationForm),
+ this.getResponseHandler(cmd, NotificationType.ERROR, rawValue, configurationForm)
);
});
}
- private setValidationResult = (result: {[key: string]: any}) => {
+ private setValidationResult = (result: { [key: string]: any }) => {
this.validationResponse = result;
- }
+ };
onValidationFormSubmit(validationForm: FormGroup): void {
this.validationResponse = null;
const rawValue = validationForm.getRawValue();
+ rawValue.componentName = rawValue.componentName[0].value;
const request$: Observable<Response> = this.shipperConfigurationService.testConfiguration(rawValue);
request$.subscribe(
- this.getResponseHandler('validate', NotificationType.SUCCESS, validationForm),
- this.getResponseHandler('validate', NotificationType.ERROR, validationForm)
+ this.getResponseHandler('validate', NotificationType.SUCCESS, rawValue, validationForm),
+ this.getResponseHandler('validate', NotificationType.ERROR, rawValue, validationForm)
);
request$
.filter((response: Response): boolean => response.ok)
@@ -178,5 +197,4 @@
canDeactivate() {
return this.configurationFormRef.canDeactivate();
}
-
}
diff --git a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html
index 7e91137..742eb1d 100644
--- a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html
+++ b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.html
@@ -14,52 +14,78 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<ng-template #typeAheadTpl let-item="item">
- {{item | translate}}
-</ng-template>
+<ng-template #typeAheadTpl let-item="item"> {{ item | translate }} </ng-template>
<div class="container-fluid">
<div class="row">
<div class="shipper-form-configuration col-md-6">
<form [formGroup]="configurationForm" (ngSubmit)="onConfigurationSubmit($event)">
<fieldset [disabled]="disabled">
- <h2>{{(serviceName ? 'shipperConfiguration.form.titleEdit' : 'shipperConfiguration.form.titleAdd') | translate}}</h2>
- <div [ngClass]="{'has-error': serviceNameField.invalid, 'form-group': true}">
+ <h2>
+ {{
+ (serviceName ? 'shipperConfiguration.form.titleEdit' : 'shipperConfiguration.form.titleAdd') | translate
+ }}
+ </h2>
+ <div
+ [ngClass]="{
+ 'has-error': serviceNameField.invalid && configurationForm.touched,
+ 'form-group': true
+ }"
+ >
<label>
- {{'shipperConfiguration.form.serviceLabel' | translate}}
- <span *ngIf="serviceNameField.errors && serviceNameField.errors.serviceNameExists"
- class="help-block validation-block pull-right">
- {{'shipperConfiguration.form.errors.serviceName.exists' | translate}}
+ {{ 'shipperConfiguration.form.serviceLabel' | translate }}
+ <span
+ *ngIf="serviceNameField.errors && serviceNameField.errors.serviceNameExists"
+ class="help-block validation-block pull-right"
+ >
+ {{ 'shipperConfiguration.form.errors.serviceName.exists' | translate }}
</span>
- <span *ngIf="serviceNameField.errors && serviceNameField.errors.required"
- class="help-block validation-block pull-right">
- {{'common.form.errors.required' | translate}}
+ <span
+ *ngIf="serviceNameField.errors && serviceNameField.errors.required"
+ class="help-block validation-block pull-right"
+ >
+ {{ 'common.form.errors.required' | translate }}
</span>
</label>
- <input *ngIf="!serviceName" formControlName="serviceName" class="form-control">
+ <input *ngIf="!serviceName" formControlName="serviceName" class="form-control" />
<ng-container *ngIf="serviceName">
- <div class="shipper-configuration-service-name">{{serviceName}}</div>
- <input type="hidden" name="serviceName" formControlName="serviceName">
+ <div class="shipper-configuration-service-name">{{ serviceName }}</div>
+ <input type="hidden" name="serviceName" formControlName="serviceName" />
</ng-container>
</div>
- <input type="hidden" name="clusterName" formControlName="clusterName">
- <div [ngClass]="{'has-error': configurationField.invalid, 'form-group': true}">
+ <input type="hidden" name="clusterName" formControlName="clusterName" />
+ <div
+ [ngClass]="{
+ 'has-error': configurationField.invalid,
+ 'form-group': true
+ }"
+ >
<label>
- {{'shipperConfiguration.form.configurationJSONLabel' | translate}}
- <span *ngIf="configurationField.errors && configurationField.errors.invalidJSON"
- class="help-block validation-block pull-right">
- {{'shipperConfiguration.form.errors.configuration.invalidJSON' | translate}}
+ {{ 'shipperConfiguration.form.configurationJSONLabel' | translate }}
+ <span
+ *ngIf="configurationField.errors && configurationField.errors.invalidJSON"
+ class="help-block validation-block pull-right"
+ >
+ {{ 'shipperConfiguration.form.errors.configuration.invalidJSON' | translate }}
</span>
- <span *ngIf="configurationField.errors && configurationField.errors.required"
- class="help-block validation-block pull-right">
- {{'common.form.errors.required' | translate}}
+ <span
+ *ngIf="configurationField.errors && configurationField.errors.required"
+ class="help-block validation-block pull-right"
+ >
+ {{ 'common.form.errors.required' | translate }}
</span>
</label>
- <textarea class="form-control configuration" name="configuration"
- formControlName="configuration"></textarea>
+ <textarea
+ class="form-control configuration"
+ name="configuration"
+ formControlName="configuration"
+ ></textarea>
</div>
- <button class="btn btn-primary pull-right" type="submit"
- [disabled]="(!configurationForm.valid || configurationForm.pristine)">
- {{'shipperConfiguration.form.saveBtn.label' | translate}}
+ <button
+ class="btn btn-primary pull-right"
+ type="submit"
+ [disabled]="!configurationForm.valid || configurationForm.pristine"
+ >
+ {{ 'shipperConfiguration.form.saveBtn.label' | translate }}
</button>
</fieldset>
</form>
@@ -68,47 +94,67 @@
<div class="container-fluid">
<div class="row">
<form [formGroup]="validatorForm" (ngSubmit)="onValidationSubmit($event)">
- <h2>{{'shipperConfiguration.validator.title' | translate}}</h2>
- <input type="hidden" name="clusterName" formControlName="clusterName">
+ <h2>{{ 'shipperConfiguration.validator.title' | translate }}</h2>
+ <input type="hidden" name="clusterName" formControlName="clusterName" />
<div class="form-group" [class.has-warning]="componentNameField.invalid">
<label>
- {{'shipperConfiguration.validator.componentNameLabel' | translate}}
- <span [class.hide]="!componentNameField.errors || !componentNameField.errors.required"
- class="help-block validation-block pull-right">
- {{'common.form.errors.required' | translate}}
+ <span
+ [class.hide]="
+ !componentNameField.errors || !componentNameField.errors.required || configurationForm.invalid
+ "
+ class="help-block validation-block pull-right"
+ >
+ {{ 'common.form.errors.required' | translate }}
</span>
- <span [class.hide]="!componentNameField.value || !componentNameField.errors || !componentNameField.errors.serviceNameDoesNotExistInConfiguration"
- class="help-block validation-block pull-right">
- {{'shipperConfiguration.form.errors.componentNameField.serviceNameDoesNotExistInConfiguration' | translate}}
+ <span
+ [class.hide]="
+ !componentNameField.value ||
+ !componentNameField.errors ||
+ !componentNameField.errors.serviceNameDoesNotExistInConfiguration
+ "
+ class="help-block validation-block pull-right"
+ >
+ {{
+ 'shipperConfiguration.form.errors.componentNameField.serviceNameDoesNotExistInConfiguration'
+ | translate
+ }}
</span>
</label>
- <input class="form-control component-name" name="componentName" formControlName="componentName"
- [typeahead]="configurationComponents$ | async"
- [typeaheadItemTemplate]="typeAheadTpl"
- [typeaheadMinLength]="0"
- [disableControl]="configurationForm.invalid"
- autocomplete="off">
+ <filter-dropdown
+ [options]="configurationComponentsList$ | async"
+ formControlName="componentName"
+ [label]="'shipperConfiguration.validator.componentNameLabel' | translate"
+ [showCommonLabelWithSelection]="true"
+ [disabled]="configurationForm.invalid || !(configurationComponentsList$ | async).length"
+ ></filter-dropdown>
</div>
<div class="form-group" [class.has-warning]="sampleDataField.invalid">
<label>
- {{'shipperConfiguration.validator.sampleDataLabel' | translate}}
- <span [class.hide]="!sampleDataField.errors || !sampleDataField.errors.required"
- class="help-block validation-block pull-right">
- {{'common.form.errors.required' | translate}}
+ {{ 'shipperConfiguration.validator.sampleDataLabel' | translate }}
+ <span
+ [class.hide]="!sampleDataField.errors || !sampleDataField.errors.required"
+ class="help-block validation-block pull-right"
+ >
+ {{ 'common.form.errors.required' | translate }}
</span>
</label>
- <textarea class="form-control sample-data" name="sampleData" formControlName="sampleData"
- [disableControl]="configurationForm.invalid"></textarea>
+ <textarea
+ class="form-control sample-data"
+ name="sampleData"
+ formControlName="sampleData"
+ [disableControl]="configurationForm.invalid"
+ ></textarea>
</div>
<div *ngIf="validationResponse" class="form-group">
- <label>
- {{'shipperConfiguration.validator.result' | translate}}
- </label>
- <pre>{{validationResponse | json}}</pre>
+ <label> {{ 'shipperConfiguration.validator.result' | translate }} </label>
+ <pre>{{ validationResponse | json }}</pre>
</div>
- <button class="btn btn-default pull-right" type="submit"
- [disabled]="(!validatorForm.valid)">
- <i class="fa fa-table" aria-hidden="true"></i> {{'shipperConfiguration.form.testBtn.label' | translate}}
+ <button
+ class="btn btn-default pull-right"
+ type="submit"
+ [disabled]="validatorForm.invalid || configurationForm.invalid"
+ >
+ <i class="fa fa-table" aria-hidden="true"></i> {{ 'shipperConfiguration.form.testBtn.label' | translate }}
</button>
</form>
</div>
@@ -116,8 +162,14 @@
</div>
</div>
</div>
-<modal *ngIf="isLeavingDirtyForm" (submit)="leaveDirtyFormConfirmed()" (cancel)="leaveDirtyFormCancelled()"
- (close)="leaveDirtyFormCancelled()" showCloseButton="false" isSmallModal="true"
- title="{{'shipperConfiguration.form.leavingDirty.title' | translate}}"
- bodyText="{{'shipperConfiguration.form.leavingDirty.message' | translate}}">
+<modal
+ *ngIf="isLeavingDirtyForm"
+ (submit)="leaveDirtyFormConfirmed()"
+ (cancel)="leaveDirtyFormCancelled()"
+ (close)="leaveDirtyFormCancelled()"
+ showCloseButton="false"
+ isSmallModal="true"
+ title="{{ 'shipperConfiguration.form.leavingDirty.title' | translate }}"
+ bodyText="{{ 'shipperConfiguration.form.leavingDirty.message' | translate }}"
+>
</modal>
diff --git a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.less b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.less
index f6f3713..0fa195c 100644
--- a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.less
+++ b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.less
@@ -16,39 +16,51 @@
* limitations under the License.
*/
-@import "../../../shared/forms";
-
-textarea {
- @extend input.form-control
- min-height: 5em;
- resize: vertical;
- width: 100%;
- &.validation-result,
- &.configuration {
- min-height: 30em;
+@import '../../../shared/forms';
+:host {
+ textarea {
+ &:extend(input.form-control);
+ min-height: 5em;
+ resize: vertical;
+ width: 100%;
+ &.validation-result,
+ &.configuration {
+ min-height: 30em;
+ }
+ &.sample-data {
+ min-height: 8em;
+ }
}
- &.sample-data {
- min-height: 8em;
+ label {
+ width: 100%;
}
-}
-label {
- width: 100%;
-}
-.help-block.validation-block {
- display: none;
- font-size: .9em;
- margin: 0;
- opacity: 0;
- transition: all 1s ease-in;
-}
-.has-error, .has-warning {
.help-block.validation-block {
- display: inline-block;
- opacity: 1;
+ display: none;
+ font-size: 0.9em;
+ margin: 0;
+ opacity: 0;
+ transition: all 1s ease-in;
}
-}
+ .has-error,
+ .has-warning {
+ .help-block.validation-block {
+ display: inline-block;
+ opacity: 1;
+ }
+ }
-.shipper-form-configuration {
- background-color: @main-background-color;
- padding-bottom: 4em;
+ .shipper-form-configuration {
+ background-color: @main-background-color;
+ padding-bottom: 4em;
+ }
+
+ /deep/ filter-dropdown {
+ button,
+ button:focus {
+ padding: 0;
+ .label-before-selection {
+ font-weight: bold;
+ }
+ }
+ }
}
diff --git a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts
index b41b941..d3d319c 100644
--- a/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts
+++ b/ambari-logsearch-web/src/app/modules/shipper/components/shipper-service-configuration-form/shipper-service-configuration-form.component.ts
@@ -16,23 +16,34 @@
* limitations under the License.
*/
-import {ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges} from '@angular/core';
-import {AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators} from '@angular/forms';
-import {Observable} from 'rxjs/Observable';
-import {Subject} from 'rxjs/Subject';
-import {Observer} from 'rxjs/Observer';
+import {
+ ChangeDetectorRef,
+ Component,
+ EventEmitter,
+ Input,
+ OnChanges,
+ OnDestroy,
+ OnInit,
+ Output,
+ SimpleChanges
+} from '@angular/core';
+import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';
+import { Observable } from 'rxjs/Observable';
+import { Subject } from 'rxjs/Subject';
+import { Observer } from 'rxjs/Observer';
import 'rxjs/add/operator/startWith';
-import {CanComponentDeactivate} from '@modules/shared/services/can-deactivate-guard.service';
+import { CanComponentDeactivate } from '@modules/shared/services/can-deactivate-guard.service';
-import {ShipperCluster} from '../../models/shipper-cluster.type';
-import {ShipperClusterService} from '../../models/shipper-cluster-service.type';
-import {ShipperClusterServiceConfigurationInterface} from '../../models/shipper-cluster-service-configuration.interface';
-import {ShipperConfigurationModel} from '../../models/shipper-configuration.model';
+import { ShipperCluster } from '../../models/shipper-cluster.type';
+import { ShipperClusterService } from '../../models/shipper-cluster-service.type';
+import { ShipperClusterServiceConfigurationInterface } from '../../models/shipper-cluster-service-configuration.interface';
+import { ShipperConfigurationModel } from '../../models/shipper-configuration.model';
import * as formValidators from '../../directives/validator.directive';
-import {BehaviorSubject} from 'rxjs/BehaviorSubject';
-import {Subscription} from 'rxjs/Subscription';
-import {ActivatedRoute} from '@angular/router';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { Subscription } from 'rxjs/Subscription';
+import { ActivatedRoute } from '@angular/router';
+import { ListItem } from '@app/classes/list-item';
@Component({
selector: 'shipper-configuration-form',
@@ -40,7 +51,6 @@
styleUrls: ['./shipper-service-configuration-form.component.less']
})
export class ShipperServiceConfigurationFormComponent implements OnInit, OnDestroy, OnChanges, CanComponentDeactivate {
-
private configurationForm: FormGroup;
private validatorForm: FormGroup;
@@ -57,7 +67,7 @@
existingServiceNames: Observable<ShipperClusterService[]> | ShipperClusterService[];
@Input()
- validationResponse: {[key: string]: any};
+ validationResponse: { [key: string]: any };
@Input()
disabled = false;
@@ -69,6 +79,7 @@
validationSubmit: EventEmitter<FormGroup> = new EventEmitter<FormGroup>();
private configurationComponents$: Observable<string[]>;
+ private configurationComponentsList$: Observable<ListItem[]>;
private isLeavingDirtyForm = false;
@@ -94,18 +105,20 @@
private canDeactivateModalResult: Subject<boolean> = new Subject<boolean>();
- private canDeactivateObservable$: Observable<boolean> = Observable.create((observer: Observer<boolean>) => {
- this.subscriptions.push(
- this.canDeactivateModalResult.subscribe((result: boolean) => {
- observer.next(result);
- })
- );
+ private canDeactivateObservable$: Observable<boolean> = Observable.create((observer: Observer<boolean>) => {
+ this.canDeactivateModalResult.takeUntil(this.destroyed$).subscribe((result: boolean) => {
+ observer.next(result);
+ });
});
- private serviceNamesListSubject: BehaviorSubject<ShipperClusterService[]> = new BehaviorSubject<ShipperClusterService[]>([]);
+ private serviceNamesListSubject: BehaviorSubject<ShipperClusterService[]> = new BehaviorSubject<
+ ShipperClusterService[]
+ >([]);
private subscriptions: Subscription[] = [];
+ private destroyed$ = new Subject();
+
constructor(
private formBuilder: FormBuilder,
private activatedRoute: ActivatedRoute,
@@ -118,33 +131,52 @@
ngOnInit() {
this.subscriptions.push(
- this.activatedRoute.params.map(params => params.service).subscribe((service) => {
- this.serviceName = service;
- })
+ this.activatedRoute.params
+ .map(params => params.service)
+ .subscribe(service => {
+ this.serviceName = service;
+ })
);
if (!this.serviceName) {
this.configurationForm.controls.serviceName.setValidators([
Validators.required,
formValidators.uniqueServiceNameValidator(this.serviceNamesListSubject)
]);
- this.changeDetectionRef.detectChanges();
}
- this.configurationComponents$ = this.configurationForm.controls.configuration.valueChanges.map((newValue: string): string[] => {
- let components: string[];
- try {
- const inputs: {[key: string]: any}[] = (newValue ? JSON.parse(newValue) : {}).input;
- components = inputs && inputs.length ? inputs.map(input => input.type) : [];
- } catch (error) {
- components = [];
- }
- return components;
- }).startWith([]);
+ this.configurationComponents$ = this.configurationForm.controls.configuration.valueChanges
+ .map(
+ (newValue: string): string[] => {
+ let components: string[];
+ try {
+ const inputs: { [key: string]: any }[] = (newValue ? JSON.parse(newValue) : {}).input;
+ components = inputs && inputs.length ? inputs.map(input => input.type) : [];
+ } catch (error) {
+ components = [];
+ }
+ return components || [];
+ }
+ )
+ .startWith([]);
+ this.configurationComponentsList$ = this.configurationComponents$
+ .map(
+ (components: string[]): ListItem[] =>
+ components
+ .filter((component: string) => component)
+ .map(
+ (component: string, index: number): ListItem => {
+ return {
+ value: component,
+ label: component,
+ isChecked: index === 0
+ };
+ }
+ )
+ )
+ .startWith([]);
if (this.existingServiceNames instanceof Observable) {
- this.subscriptions.push(
- this.existingServiceNames.subscribe((serviceNames: ShipperClusterService[]) => {
- this.serviceNamesListSubject.next(serviceNames);
- })
- );
+ this.existingServiceNames.takeUntil(this.destroyed$).subscribe((serviceNames: ShipperClusterService[]) => {
+ this.serviceNamesListSubject.next(serviceNames);
+ });
} else {
this.serviceNamesListSubject.next(this.existingServiceNames);
}
@@ -168,7 +200,11 @@
}
});
}
- if (this.validatorForm && changes.clusterName && this.validatorForm.controls.clusterName.value !== changes.clusterName.currentValue) {
+ if (
+ this.validatorForm &&
+ changes.clusterName &&
+ this.validatorForm.controls.clusterName.value !== changes.clusterName.currentValue
+ ) {
this.validatorForm.controls.clusterName.setValue(changes.clusterName.currentValue);
this.validatorForm.markAsPristine();
}
@@ -178,17 +214,18 @@
if (this.subscriptions) {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
+ this.destroyed$.next(true);
}
leaveDirtyFormConfirmed = () => {
this.canDeactivateModalResult.next(true);
this.isLeavingDirtyForm = false;
- }
+ };
leaveDirtyFormCancelled = () => {
this.canDeactivateModalResult.next(false);
this.isLeavingDirtyForm = false;
- }
+ };
canDeactivate(): Observable<boolean> {
if (this.configurationForm.pristine) {
@@ -203,39 +240,33 @@
}
createForms(): void {
- const configuration: ShipperClusterServiceConfigurationInterface = this.configuration || (
- this.serviceName ? this.configuration : new ShipperConfigurationModel()
- );
+ const configuration: ShipperClusterServiceConfigurationInterface =
+ this.configuration || (this.serviceName ? this.configuration : new ShipperConfigurationModel());
this.configurationForm = this.formBuilder.group({
clusterName: this.formBuilder.control(this.clusterName, Validators.required),
- serviceName: this.formBuilder.control(
- this.serviceName,
- [Validators.required]
- ),
- configuration: this.formBuilder.control(
- this.getConfigurationAsString(configuration),
- [Validators.required, formValidators.configurationValidator()]
- )
+ serviceName: this.formBuilder.control(this.serviceName, [Validators.required]),
+ configuration: this.formBuilder.control(this.getConfigurationAsString(configuration), [
+ Validators.required,
+ formValidators.configurationValidator()
+ ])
});
this.validatorForm = this.formBuilder.group({
- clusterName: this.formBuilder.control(
- this.clusterName,
- [Validators.required]
- ),
+ clusterName: this.formBuilder.control(this.clusterName, [Validators.required]),
componentName: this.formBuilder.control('', [
Validators.required,
- formValidators.getConfigurationServiceValidator(this.configurationForm.controls.configuration)
+ formValidators.getConfigurationServiceValidator(
+ this.configurationForm.controls.configuration,
+ listItem => listItem && listItem.length && listItem[0].value
+ )
]),
sampleData: this.formBuilder.control('', Validators.required),
configuration: this.formBuilder.control('', Validators.required)
});
- this.subscriptions.push(
- this.configurationForm.valueChanges.subscribe(() => {
- this.validatorForm.controls.componentName.updateValueAndValidity();
- this.validatorForm.controls.configuration.setValue(this.configurationForm.controls.configuration.value);
- })
- );
+ this.configurationForm.valueChanges.takeUntil(this.destroyed$).subscribe(() => {
+ this.validatorForm.controls.componentName.updateValueAndValidity();
+ this.validatorForm.controls.configuration.setValue(this.configurationForm.controls.configuration.value);
+ });
}
onConfigurationSubmit(): void {
@@ -249,5 +280,4 @@
this.validationSubmit.emit(this.validatorForm);
}
}
-
}
diff --git a/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts b/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts
index 50c1237..a590125 100644
--- a/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts
+++ b/ambari-logsearch-web/src/app/modules/shipper/directives/validator.directive.ts
@@ -16,46 +16,49 @@
* limitations under the License.
*/
-import {AbstractControl, ValidatorFn} from '@angular/forms';
-import {ShipperClusterService} from '@modules/shipper/models/shipper-cluster-service.type';
-import {ValidationErrors} from '@angular/forms/src/directives/validators';
-import {BehaviorSubject} from 'rxjs/BehaviorSubject';
+import { AbstractControl, ValidatorFn } from '@angular/forms';
+import { ShipperClusterService } from '@modules/shipper/models/shipper-cluster-service.type';
+import { ValidationErrors } from '@angular/forms/src/directives/validators';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
export function configurationValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
try {
- const json: {[key: string]: any} = JSON.parse(control.value);
+ const json: { [key: string]: any } = JSON.parse(control.value);
return null;
} catch (error) {
return {
- invalidJSON: {value: control.value}
+ invalidJSON: { value: control.value }
};
}
};
}
-export function uniqueServiceNameValidator(
- serviceNames: BehaviorSubject<ShipperClusterService[]>
-): ValidatorFn {
+export function uniqueServiceNameValidator(serviceNames: BehaviorSubject<ShipperClusterService[]>): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const services: ShipperClusterService[] = serviceNames.getValue();
- return services && services.indexOf(control.value) > -1 ? {
- serviceNameExists: {value: control.value}
- } : null;
+ return services && services.indexOf(control.value) > -1
+ ? {
+ serviceNameExists: { value: control.value }
+ }
+ : null;
};
}
-export function getConfigurationServiceValidator(configControl: AbstractControl): ValidatorFn {
+export function getConfigurationServiceValidator(configControl: AbstractControl, valueMapper?: Function): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
let components: string[];
try {
- const inputs: {[key: string]: any}[] = (configControl.value ? JSON.parse(configControl.value) : {}).input;
+ const inputs: { [key: string]: any }[] = (configControl.value ? JSON.parse(configControl.value) : {}).input;
components = inputs && inputs.length ? inputs.map(input => input.type) : [];
} catch (error) {
components = [];
}
- return components.length && components.indexOf(control.value) === -1 ? {
- serviceNameDoesNotExistInConfiguration: {value: control.value}
- } : null;
+ const value = valueMapper ? valueMapper(control.value) : control.value;
+ return components.length && components.indexOf(value) === -1
+ ? {
+ serviceNameDoesNotExistInConfiguration: { value: value }
+ }
+ : null;
};
}