Commit 041a489f authored by AllForNothing's avatar AllForNothing
Browse files

Add name and endpoint check for p2p-preheat


Signed-off-by: default avatarAllForNothing <sshijun@vmware.com>
parent 19234cdb
......@@ -16,6 +16,7 @@ $refrsh-btn-color: #007CBB;
}
.action-head-pos {
padding-top: 12px;
padding-right: 18px;
height: 24px;
display: flex;
......
......@@ -33,24 +33,30 @@
</clr-select-container>
<!-- 2. name -->
<clr-input-container>
<label class="required clr-control-label" for="name">{{
'DISTRIBUTION.NAME' | translate
}}</label>
<input class="width-280"
clrInput
required
type="text"
id="name"
autocomplete="off"
[(ngModel)]="model.name"
name="name"
[disabled]="editingMode"
/>
<clr-control-error>
{{ 'TOOLTIP.ITEM_REQUIRED' | translate }}
</clr-control-error>
</clr-input-container>
<div class="clr-form-control">
<label class="required clr-control-label" for="name">{{'DISTRIBUTION.NAME' | translate}}</label>
<div class="clr-control-container" [class.clr-error]="((nameNg.dirty || nameNg.touched) && nameNg.invalid) || isNameExisting">
<div class="clr-input-wrapper">
<input class="width-280 clr-input"
required
type="text"
id="name"
autocomplete="off"
[(ngModel)]="model.name"
name="name"
#nameNg="ngModel"
[disabled]="editingMode"
(input)="inputName()"
/>
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
<span class="spinner spinner-inline" [hidden]="!checkNameOnGoing"></span>
</div>
<clr-control-error *ngIf="((nameNg.dirty || nameNg.touched) && nameNg.invalid) || isNameExisting">
<span *ngIf="!((nameNg.dirty || nameNg.touched) && nameNg.invalid) && isNameExisting">{{'SCANNER.NAME_EXISTS' | translate}}</span>
<span *ngIf="(nameNg.dirty || nameNg.touched) && nameNg.invalid">{{ 'TOOLTIP.ITEM_REQUIRED' | translate }}</span>
</clr-control-error>
</div>
</div>
<!-- 3. description -->
<clr-textarea-container>
......@@ -65,27 +71,32 @@
[ngModelOptions]="{ standalone: true }"
></textarea>
</clr-textarea-container>
<!-- 4. endpoint -->
<clr-input-container>
<label class="required clr-control-label" for="endpoint">{{
'DISTRIBUTION.ENDPOINT' | translate
}}</label>
<input class="width-280"
clrInput
required
pattern="^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(.*?)*$"
type="text"
id="endpoint"
placeholder="http(s)://192.168.1.1"
[(ngModel)]="model.endpoint"
name="endpoint"
autocomplete="off"
/>
<clr-control-error>{{
'TOOLTIP.ENDPOINT_FORMAT' | translate
}}</clr-control-error>
</clr-input-container>
<div class="clr-form-control">
<label class="required clr-control-label" for="name">{{'DISTRIBUTION.ENDPOINT' | translate}}</label>
<div class="clr-control-container" [class.clr-error]="((endpointNg.dirty || endpointNg.touched) && endpointNg.invalid) || isEndpointExisting">
<div class="clr-input-wrapper">
<input class="width-280 clr-input"
required
pattern="^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(.*?)*$"
type="text"
id="endpoint"
placeholder="http(s)://192.168.1.1"
[(ngModel)]="model.endpoint"
name="endpoint"
#endpointNg="ngModel"
autocomplete="off"
(input)="inputEndpoint()"
/>
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
<span class="spinner spinner-inline" [hidden]="!checkEndpointOngoing"></span>
</div>
<clr-control-error *ngIf="((endpointNg.dirty || endpointNg.touched) && endpointNg.invalid) || isEndpointExisting">
<span *ngIf="!((endpointNg.dirty || endpointNg.touched) && endpointNg.invalid) && isEndpointExisting">{{'SCANNER.ENDPOINT_EXISTS' | translate}}</span>
<span *ngIf="(endpointNg.dirty || endpointNg.touched) && endpointNg.invalid">{{ 'TOOLTIP.ENDPOINT_FORMAT' | translate }}</span>
</clr-control-error>
</div>
</div>
<!-- auth mode -->
<clr-radio-container clrInline>
<label>{{ 'DISTRIBUTION.AUTH_MODE' | translate }}</label>
......@@ -232,7 +243,7 @@
</form>
</div>
<div class="modal-footer">
<button id="button-test" type="button" [clrLoading]="checkBtnState" class="btn btn-outline" (click)="onTestEndpoint()" [disabled]="!isValid || onTesting">{{'SCANNER.TEST_CONNECTION' | translate}}</button>
<button id="button-test" type="button" [clrLoading]="checkBtnState" class="btn btn-outline" (click)="onTestEndpoint()" [disabled]="!isValid || onTesting || checkNameOnGoing || checkEndpointOngoing || isEndpointExisting || isNameExisting">{{'SCANNER.TEST_CONNECTION' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="cancel()">
{{ 'BUTTON.CANCEL' | translate }}
</button>
......@@ -241,7 +252,7 @@
type="button"
class="btn btn-primary"
(click)="submit()"
[disabled]="!isValid || !hasChangesForEdit()"
[disabled]="!isValid || !hasChangesForEdit() || checkNameOnGoing || checkEndpointOngoing"
>
{{ 'BUTTON.OK' | translate }}
</button>
......
......@@ -7,6 +7,8 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { DistributionSetupModalComponent } from './distribution-setup-modal.component';
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service";
import { Instance } from '../../../../ng-swagger-gen/models/instance';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
describe('DistributionSetupModalComponent', () => {
let component: DistributionSetupModalComponent;
......@@ -24,6 +26,11 @@ describe('DistributionSetupModalComponent', () => {
vendor: 'kraken',
status: 'Healthy'
};
const fakedPreheatService = {
ListInstances() {
return of([]).pipe(delay(0));
}
};
beforeEach(async(() => {
TestBed.configureTestingModule({
......@@ -34,7 +41,7 @@ describe('DistributionSetupModalComponent', () => {
HttpClientTestingModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [PreheatService],
providers: [ { provide: PreheatService, useValue: fakedPreheatService }],
declarations: [DistributionSetupModalComponent]
}).compileComponents();
}));
......
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { NgForm, Validators } from '@angular/forms';
import {
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
ViewChild
} from '@angular/core';
import { NgForm } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { errorHandler } from '../../../lib/utils/shared/shared.utils';
import { PreheatService } from '../../../../ng-swagger-gen/services/preheat.service';
import { Instance } from '../../../../ng-swagger-gen/models/instance';
import { AuthMode, FrontInstance, HEALTHY } from '../distribution-interface';
import { AuthMode, FrontInstance } from '../distribution-interface';
import { clone } from '../../../lib/utils/utils';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { ClrLoadingState } from '@clr/angular';
import { Metadata } from '../../../../ng-swagger-gen/models/metadata';
import { operateChanges, OperateInfo, OperationState } from '../../../lib/components/operation/operate';
import { OperationService } from '../../../lib/components/operation/operation.service';
import { finalize } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, filter, finalize, switchMap } from 'rxjs/operators';
import { Subject, Subscription } from 'rxjs';
const DEFAULT_PROVIDER: string = 'dragonfly';
......@@ -21,7 +30,7 @@ const DEFAULT_PROVIDER: string = 'dragonfly';
templateUrl: './distribution-setup-modal.component.html',
styleUrls: ['./distribution-setup-modal.component.scss']
})
export class DistributionSetupModalComponent implements OnInit {
export class DistributionSetupModalComponent implements OnInit, OnDestroy {
@Input()
providers: Metadata[] = [];
model: Instance;
......@@ -37,6 +46,14 @@ export class DistributionSetupModalComponent implements OnInit {
refresh: EventEmitter<any> = new EventEmitter<any>();
checkBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
onTesting: boolean = false;
private _nameSubject: Subject<string> = new Subject<string>();
private _endpointSubject: Subject<string> = new Subject<string>();
private _nameSubscription: Subscription;
private _endpointSubscription: Subscription;
isNameExisting: boolean = false;
isEndpointExisting: boolean = false;
checkNameOnGoing: boolean = false;
checkEndpointOngoing: boolean = false;
constructor(
private distributionService: PreheatService,
private msgHandler: MessageHandlerService,
......@@ -45,8 +62,72 @@ export class DistributionSetupModalComponent implements OnInit {
) {}
ngOnInit() {
this.subscribeName();
this.subscribeEndpoint();
this.reset();
}
ngOnDestroy() {
if (this._nameSubscription) {
this._nameSubscription.unsubscribe();
this._nameSubscription = null;
}
if (this._endpointSubscription) {
this._endpointSubscription.unsubscribe();
this._endpointSubscription = null;
}
}
subscribeName() {
if (!this._nameSubscription) {
this._nameSubscription = this._nameSubject
.pipe(
debounceTime(500),
distinctUntilChanged(),
filter(name => {
return name.length > 0;
}),
switchMap((name) => {
this.isNameExisting = false;
this.checkNameOnGoing = true;
return this.distributionService.ListInstances({
q: encodeURIComponent(`name=${name}`)
}).pipe(finalize(() => this.checkNameOnGoing = false));
}))
.subscribe(res => {
if (res && res.length > 0) {
this.isNameExisting = true;
}
});
}
}
subscribeEndpoint() {
if (!this._endpointSubscription) {
this._endpointSubscription = this._endpointSubject
.pipe(
debounceTime(500),
distinctUntilChanged(),
filter(endpoint => {
return this.instanceForm.control.get('endpoint').valid;
}),
switchMap((endpoint) => {
this.isEndpointExisting = false;
this.checkEndpointOngoing = true;
return this.distributionService.ListInstances({
q: encodeURIComponent(`endpoint=${endpoint}`)
}).pipe(finalize(() => this.checkEndpointOngoing = false));
}))
.subscribe(res => {
if (res && res.length > 0) {
this.isEndpointExisting = true;
}
});
}
}
inputName() {
this._nameSubject.next(this.model.name);
}
inputEndpoint() {
this._endpointSubject.next(this.model.endpoint);
}
public get isValid(): boolean {
return this.instanceForm && this.instanceForm.valid;
}
......@@ -100,7 +181,10 @@ export class DistributionSetupModalComponent implements OnInit {
auth_mode: AuthMode.NONE,
auth_info: this.authData
};
this.instanceForm.reset();
this.instanceForm.reset({
enabled: true,
insecure: true,
});
}
cancel() {
......@@ -190,6 +274,7 @@ export class DistributionSetupModalComponent implements OnInit {
this.originModelForEdit = clone(data);
this.authData = this.model.auth_info || {};
} else {
this.reset();
if (this.providers && this.providers.length) {
this.providers.forEach(item => {
if (item.id === DEFAULT_PROVIDER) {
......
......@@ -34,14 +34,16 @@
<!-- name -->
<div class="clr-form-control">
<label for="name" class="clr-control-label required width-6rem">{{'P2P_PROVIDER.NAME' | translate}}</label>
<div class="clr-control-container" [class.clr-error]="name.errors && name.errors.required && (name.dirty || name.touched)">
<div class="clr-control-container" [class.clr-error]="((name.dirty || name.touched) && name.invalid) || isNameExisting">
<div class="clr-input-wrapper">
<input pattern="^[a-z0-9]+(?:[._-][a-z0-9]+)*$" [disabled]="loading" autocomplete="off" class="clr-input width-380" type="text" id="name" [(ngModel)]="policy.name"
size="30" name="name" #name="ngModel" required>
size="30" name="name" #name="ngModel" required (input)="inputName()">
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
<span class="spinner spinner-inline" [hidden]="!checkNameOnGoing"></span>
</div>
<clr-control-error *ngIf="name.errors && name.errors.required && (name.dirty || name.touched)" class="tooltip-content">
{{'P2P_PROVIDER.NAME_REQUIRED' | translate}}
<clr-control-error *ngIf="((name.dirty || name.touched) && name.invalid) || isNameExisting">
<span *ngIf="!((name.dirty || name.touched) && name.invalid) && isNameExisting">{{'SCANNER.NAME_EXISTS' | translate}}</span>
<span *ngIf="(name.dirty || name.touched) && name.invalid">{{ 'PROJECT.NAME_TOOLTIP' | translate }}</span>
</clr-control-error>
</div>
</div>
......@@ -172,12 +174,12 @@
</form>
<div class="mt-1 bottom-btn" *ngIf="!isEdit">
<button type="button" class="btn btn-outline" id="add-policy-cancel" (click)="onCancel()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" id="new-policy" class="btn btn-primary" [clrLoading]="buttonStatus" [disabled]="loading || !valid()" (click)="addOrSave(true)">{{'BUTTON.ADD' | translate}}</button>
<button type="button" id="new-policy" class="btn btn-primary" [clrLoading]="buttonStatus" [disabled]="isNameExisting ||checkNameOnGoing || loading || !valid()" (click)="addOrSave(true)">{{'BUTTON.ADD' | translate}}</button>
</div>
<div class="mt-1 bottom-btn" *ngIf="isEdit">
<button type="button" class="btn btn-outline" id="edit-policy-cancel" (click)="onCancel()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-primary" id="edit-policy-save"
[clrLoading]="buttonStatus" [disabled]="loading || !valid() || !hasChange()" (click)="addOrSave(false)">{{'BUTTON.SAVE' | translate}}</button>
[clrLoading]="buttonStatus" [disabled]="isNameExisting || checkNameOnGoing || loading || !valid() || !hasChange()" (click)="addOrSave(false)">{{'BUTTON.SAVE' | translate}}</button>
</div>
</div>
</div>
......
......@@ -33,6 +33,9 @@ describe('AddP2pPolicyComponent', () => {
},
UpdatePolicy() {
return of(true).pipe(delay(0));
},
ListPolicies() {
return of([]).pipe(delay(0));
}
};
const mockActivatedRoute = {
......@@ -135,7 +138,7 @@ describe('AddP2pPolicyComponent', () => {
nameInput.dispatchEvent(new Event('input'));
nameInput.blur();
const errorEle: HTMLElement = fixture.nativeElement.querySelector("clr-control-error");
expect(errorEle.innerText).toEqual('P2P_PROVIDER.NAME_REQUIRED');
expect(errorEle.innerText).toEqual('PROJECT.NAME_TOOLTIP');
});
it("save button should work", async () => {
fixture.autoDetectChanges(true);
......
import { Component, EventEmitter, Input, OnInit, Output, ViewChild, } from '@angular/core';
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild, } from '@angular/core';
import { PreheatPolicy } from '../../../../../ng-swagger-gen/models/preheat-policy';
import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component';
import { NgForm } from '@angular/forms';
import { OriginCron, ProjectService } from '../../../../lib/services';
import { CronScheduleComponent } from '../../../../lib/components/cron-schedule';
import { PreheatService } from '../../../../../ng-swagger-gen/services/preheat.service';
import { finalize } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, filter, finalize, switchMap } from 'rxjs/operators';
import { deleteEmptyKey } from '../../../../lib/utils/utils';
import { ClrLoadingState } from '@clr/angular';
import { SessionService } from '../../../shared/session.service';
......@@ -14,6 +14,7 @@ import { ActivatedRoute } from '@angular/router';
import { FILTER_TYPE, PROJECT_SEVERITY_LEVEL_MAP, TRIGGER, TRIGGER_I18N_MAP } from '../p2p-provider.service';
import { ProviderUnderProject } from '../../../../../ng-swagger-gen/models/provider-under-project';
import { AppConfigService } from '../../../services/app-config.service';
import { Subject, Subscription } from 'rxjs';
const SCHEDULE_TYPE = {
NONE: "None",
......@@ -28,7 +29,7 @@ const TRUE: string = 'true';
templateUrl: './add-p2p-policy.component.html',
styleUrls: ['./add-p2p-policy.component.scss']
})
export class AddP2pPolicyComponent implements OnInit {
export class AddP2pPolicyComponent implements OnInit, OnDestroy {
severityOptions = [
{severity: 5, severityLevel: 'VULNERABILITY.SEVERITY.CRITICAL'},
{severity: 4, severityLevel: 'VULNERABILITY.SEVERITY.HIGH'},
......@@ -73,7 +74,10 @@ export class AddP2pPolicyComponent implements OnInit {
projectSeverity: string;
triggers: string[] = [TRIGGER.MANUAL, TRIGGER.SCHEDULED, TRIGGER.EVENT_BASED];
enableContentTrust: boolean = false;
private _nameSubject: Subject<string> = new Subject<string>();
private _nameSubscription: Subscription;
isNameExisting: boolean = false;
checkNameOnGoing: boolean = false;
constructor(private preheatService: PreheatService,
private session: SessionService,
private route: ActivatedRoute,
......@@ -90,6 +94,43 @@ export class AddP2pPolicyComponent implements OnInit {
// get latest project info
this.getProject();
}
this.subscribeName();
}
ngOnDestroy() {
if (this._nameSubscription) {
this._nameSubscription.unsubscribe();
this._nameSubscription = null;
}
}
subscribeName() {
if (!this._nameSubscription) {
this._nameSubscription = this._nameSubject
.pipe(
debounceTime(500),
distinctUntilChanged(),
filter(name => {
if (this.isEdit && this.originPolicyForEdit && this.originPolicyForEdit.name === name) {
return false;
}
return name.length > 0;
}),
switchMap((name) => {
this.isNameExisting = false;
this.checkNameOnGoing = true;
return this.preheatService.ListPolicies({
projectName: this.projectName,
q: encodeURIComponent(`name=${name}`)
}).pipe(finalize(() => this.checkNameOnGoing = false));
}))
.subscribe(res => {
if (res && res.length > 0) {
this.isNameExisting = true;
}
});
}
}
inputName() {
this._nameSubject.next(this.policy.name);
}
getProject() {
this.projectService.getProject(this.projectId)
......@@ -115,6 +156,13 @@ export class AddP2pPolicyComponent implements OnInit {
severity: PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity],
onlySignedImages: this.enableContentTrust
});
if (this.providers && this.providers.length) {
this.providers.forEach(item => {
if (item.default) {
this.policy.provider_id = item.id;
}
});
}
}
setCron(event: any) {
......
......@@ -77,7 +77,7 @@
</clr-dg-action-bar>
<clr-dg-column [clrDgField]="'name'">{{'P2P_PROVIDER.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'P2P_PROVIDER.ENABLED' | translate}}</clr-dg-column>
<clr-dg-column>{{'P2P_PROVIDER.PROVIDER' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'provider_name'">{{'P2P_PROVIDER.PROVIDER' | translate}}</clr-dg-column>
<clr-dg-column>{{'P2P_PROVIDER.FILTERS' | translate}}</clr-dg-column>
<clr-dg-column>{{'P2P_PROVIDER.TRIGGER' | translate}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="creationTimeComparator">{{'P2P_PROVIDER.CREATED' | translate}}</clr-dg-column>
......@@ -164,20 +164,19 @@
<select id="selectKey" (change)="selectFilterKey($event)">
<option value="id">{{"P2P_PROVIDER.ID" | translate | lowercase}}</option>
<option value="status">{{"REPLICATION.STATUS" | translate | lowercase}}</option>
<option value="vendor_type">{{"P2P_PROVIDER.PROVIDER_TYPE" | translate | lowercase}}</option>
</select>
</div>
<hbr-filter (filterEvt)="doFilter($event)" [currentValue]="searchString" id="filter-executions" [withDivider]="true"
(openFlag)="openFilter($event)" filterPlaceholder='{{"REPLICATION.FILTER_EXECUTIONS_PLACEHOLDER" | translate}}'></hbr-filter>
<span class="refresh-btn">
<clr-icon shape="refresh" (click)="refresh()" [hidden]="loading"></clr-icon>
<clr-icon shape="refresh" (click)="refreshJobs()" [hidden]="loading"></clr-icon>
</span>
</div>
</div>
</clr-dg-action-bar>
<clr-dg-column>{{'REPLICATION.ID' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.REPLICATION_TRIGGER' | translate}}</clr-dg-column>
<clr-dg-column>{{'P2P_PROVIDER.TRIGGER' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.DURATION' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.SUCCESS_RATE' | translate}}</clr-dg-column>
......@@ -196,7 +195,7 @@
</clr-tooltip-content>
</clr-tooltip>
</clr-dg-cell>
<clr-dg-cell>{{execution.trigger}}</clr-dg-cell>
<clr-dg-cell>{{getTriggerTypeI18nForExecution(execution.trigger) | translate}}</clr-dg-cell>
<clr-dg-cell>{{execution.start_time | date: 'short'}}</clr-dg-cell>
<clr-dg-cell>{{getDuration(execution)}}</clr-dg-cell>
<clr-dg-cell>{{getSuccessRate(execution.metrics)}}</clr-dg-cell>
......@@ -206,7 +205,7 @@
<span *ngIf="totalExecutionCount">{{pagination.firstItem + 1}}
- {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
{{totalExecutionCount}} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentExecutionPage" [clrDgPageSize]="10"
<clr-dg-pagination #pagination [(clrDgPage)]="currentExecutionPage" [clrDgPageSize]="pageSize"
[clrDgTotalItems]="totalExecutionCount"></clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
......
......@@ -33,7 +33,7 @@
cursor: pointer;
}
.filter-tag {
margin-top: 6px;
margin-top: 7px;
}
.filter-title {
font-weight: 400;
......
......@@ -11,7 +11,7 @@
// 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 { distinctUntilChanged, finalize, switchMap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, finalize, switchMap } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
......@@ -106,10 +106,7 @@ export class PolicyComponent implements OnInit, OnDestroy {
this._searchSubscription.unsubscribe();
this._searchSubscription = null;
}
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
this.clearLoop();
}
getPermissions() {
const permissionsList: Observable<boolean>[] = [];
......@@ -134,7 +131,11 @@ export class PolicyComponent implements OnInit, OnDestroy {
getProviders() {
this.preheatService.ListProvidersUnderProject({projectName: this.projectName})
.subscribe(res => {
this.providers = res;
if (res && res.length) {
this.providers = res.filter(provider => {
return provider.enabled;
});
}
});
}
refresh() {
......@@ -358,23 +359,13 @@ export class PolicyComponent implements OnInit, OnDestroy {
}).pipe(finalize(() => this.jobsLoading = false))
.subscribe(response => {
if (response.headers) {
let xHeader: string = response.headers.get('x-total-count');
let xHeader: string = response.headers.get('X-Total-Count');
if (xHeader) {
this.totalExecutionCount = parseInt(xHeader, 0);
}
}
this.executionList = response.body;
if (this.executionList && this.executionList.length) {