mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 10:45:45 +01:00
Add shareable endpoint components.
This commit is contained in:
parent
c3c7b540f1
commit
5071dcf304
@ -0,0 +1,21 @@
|
|||||||
|
export const CONFIRMATION_DIALOG_STYLE: string = `
|
||||||
|
.confirmation-icon-inline {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmation-title {
|
||||||
|
line-height: 24px;
|
||||||
|
color: #000000;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmation-content {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #565656;
|
||||||
|
line-height: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 80%;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
`;
|
@ -0,0 +1,28 @@
|
|||||||
|
export const CONFIRMATION_DIALOG_TEMPLATE: string = `
|
||||||
|
<clr-modal [(clrModalOpen)]="opened" [clrModalClosable]="false" [clrModalStaticBackdrop]="true">
|
||||||
|
<h3 class="modal-title" class="confirmation-title" style="margin-top: 0px;">{{dialogTitle}}</h3>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="confirmation-icon-inline">
|
||||||
|
<clr-icon shape="warning" class="is-warning" size="64"></clr-icon>
|
||||||
|
</div>
|
||||||
|
<div class="confirmation-content">{{dialogContent}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer" [ngSwitch]="buttons">
|
||||||
|
<ng-template [ngSwitchCase]="0">
|
||||||
|
<button type="button" class="btn btn-outline" (click)="cancel()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||||
|
<button type="button" class="btn btn-primary" (click)="confirm()">{{ 'BUTTON.CONFIRM' | translate}}</button>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template [ngSwitchCase]="1">
|
||||||
|
<button type="button" class="btn btn-outline" (click)="cancel()">{{'BUTTON.NO' | translate}}</button>
|
||||||
|
<button type="button" class="btn btn-primary" (click)="confirm()">{{ 'BUTTON.YES' | translate}}</button>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template [ngSwitchCase]="2">
|
||||||
|
<button type="button" class="btn btn-outline" (click)="cancel()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||||
|
<button type="button" class="btn btn-danger" (click)="confirm()">{{ 'BUTTON.DELETE' | translate}}</button>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template [ngSwitchCase]="3">
|
||||||
|
<button type="button" class="btn btn-primary" (click)="cancel()">{{'BUTTON.CLOSE' | translate}}</button>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</clr-modal>
|
||||||
|
`;
|
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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, EventEmitter, Output } from '@angular/core';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { ConfirmationMessage } from './confirmation-message';
|
||||||
|
import { ConfirmationAcknowledgement } from './confirmation-state-message';
|
||||||
|
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../shared/shared.const';
|
||||||
|
|
||||||
|
import { CONFIRMATION_DIALOG_TEMPLATE } from './confirmation-dialog.component.html';
|
||||||
|
import { CONFIRMATION_DIALOG_STYLE } from './confirmation-dialog.component.css';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'confirmation-dialog',
|
||||||
|
template: CONFIRMATION_DIALOG_TEMPLATE,
|
||||||
|
styles: [ CONFIRMATION_DIALOG_STYLE ]
|
||||||
|
})
|
||||||
|
|
||||||
|
export class ConfirmationDialogComponent {
|
||||||
|
opened: boolean = false;
|
||||||
|
dialogTitle: string = "";
|
||||||
|
dialogContent: string = "";
|
||||||
|
message: ConfirmationMessage;
|
||||||
|
buttons: ConfirmationButtons;
|
||||||
|
|
||||||
|
@Output() confirmAction = new EventEmitter<ConfirmationAcknowledgement>();
|
||||||
|
@Output() cancelAction = new EventEmitter<ConfirmationAcknowledgement>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private translate: TranslateService) {}
|
||||||
|
|
||||||
|
open(msg: ConfirmationMessage): void {
|
||||||
|
this.dialogTitle = msg.title;
|
||||||
|
this.dialogContent = msg.message;
|
||||||
|
this.message = msg;
|
||||||
|
this.translate.get(this.dialogTitle).subscribe((res: string) => this.dialogTitle = res);
|
||||||
|
this.translate.get(this.dialogContent, { 'param': msg.param }).subscribe((res: string) => this.dialogContent = res);
|
||||||
|
//Open dialog
|
||||||
|
this.buttons = msg.buttons;
|
||||||
|
this.opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(): void {
|
||||||
|
this.opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel(): void {
|
||||||
|
if(!this.message){//Inproper condition
|
||||||
|
this.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: any = this.message.data ? this.message.data : {};
|
||||||
|
let target = this.message.targetId ? this.message.targetId : ConfirmationTargets.EMPTY;
|
||||||
|
this.cancelAction.emit(new ConfirmationAcknowledgement(
|
||||||
|
ConfirmationState.CANCEL,
|
||||||
|
data,
|
||||||
|
target
|
||||||
|
));
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm(): void {
|
||||||
|
if(!this.message){//Inproper condition
|
||||||
|
this.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: any = this.message.data ? this.message.data : {};
|
||||||
|
let target = this.message.targetId ? this.message.targetId : ConfirmationTargets.EMPTY;
|
||||||
|
let message = new ConfirmationAcknowledgement(
|
||||||
|
ConfirmationState.CONFIRMED,
|
||||||
|
data,
|
||||||
|
target
|
||||||
|
);
|
||||||
|
this.confirmAction.emit(message);
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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 { ConfirmationTargets, ConfirmationButtons } from '../shared/shared.const';
|
||||||
|
|
||||||
|
export class ConfirmationMessage {
|
||||||
|
public constructor(title: string, message: string, param: string, data: any, targetId: ConfirmationTargets, buttons?: ConfirmationButtons) {
|
||||||
|
this.title = title;
|
||||||
|
this.message = message;
|
||||||
|
this.data = data;
|
||||||
|
this.targetId = targetId;
|
||||||
|
this.param = param;
|
||||||
|
this.buttons = buttons ? buttons : ConfirmationButtons.CONFIRM_CANCEL;
|
||||||
|
}
|
||||||
|
title: string;
|
||||||
|
message: string;
|
||||||
|
data: any = {};//default is empty
|
||||||
|
targetId: ConfirmationTargets = ConfirmationTargets.EMPTY;
|
||||||
|
param: string;
|
||||||
|
buttons: ConfirmationButtons;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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 { ConfirmationState, ConfirmationTargets } from '../shared/shared.const';
|
||||||
|
|
||||||
|
export class ConfirmationAcknowledgement {
|
||||||
|
constructor(state: ConfirmationState, data: any, source: ConfirmationTargets) {
|
||||||
|
this.state = state;
|
||||||
|
this.data = data;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
state: ConfirmationState = ConfirmationState.NA;
|
||||||
|
data: any = {};
|
||||||
|
source: ConfirmationTargets = ConfirmationTargets.EMPTY;
|
||||||
|
}
|
7
src/ui_ng/lib/src/confirmation-dialog/index.ts
Normal file
7
src/ui_ng/lib/src/confirmation-dialog/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Type } from '@angular/core';
|
||||||
|
|
||||||
|
import { ConfirmationDialogComponent } from './confirmation-dialog.component';
|
||||||
|
|
||||||
|
export const CONFIRMATION_DIALOG_DIRECTIVES: Type<any>[] = [
|
||||||
|
ConfirmationDialogComponent
|
||||||
|
];
|
@ -0,0 +1,6 @@
|
|||||||
|
export const CREATE_EDIT_ENDPOINT_STYLE: string = `
|
||||||
|
.form-group-label-override {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
`;
|
@ -0,0 +1,53 @@
|
|||||||
|
export const CREATE_EDIT_ENDPOINT_TEMPLATE: string = `<clr-modal [(clrModalOpen)]="createEditDestinationOpened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalClosable]="closable">
|
||||||
|
<h3 class="modal-title">{{modalTitle}}</h3>
|
||||||
|
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-warning" *ngIf="!editable">
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">
|
||||||
|
{{'DESTINATION.CANNOT_EDIT' | translate}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form #targetForm="ngForm">
|
||||||
|
<section class="form-block">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="destination_name" class="col-md-4 form-group-label-override">{{ 'DESTINATION.NAME' | translate }}<span style="color: red">*</span></label>
|
||||||
|
<label class="col-md-8" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)" [class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
|
||||||
|
<input type="text" id="destination_name" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.name" name="targetName" size="20" #targetName="ngModel" required (keyup)="changedTargetName($event)">
|
||||||
|
<span class="tooltip-content" *ngIf="targetName.errors && targetName.errors.required && (targetName.dirty || targetName.touched)">
|
||||||
|
{{ 'DESTINATION.NAME_IS_REQUIRED' | translate }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="destination_url" class="col-md-4 form-group-label-override">{{ 'DESTINATION.URL' | translate }}<span style="color: red">*</span></label>
|
||||||
|
<label class="col-md-8" for="destination_url" aria-haspopup="true" role="tooltip" [class.invalid]="targetEndpoint.errors && (targetEndpoint.dirty || targetEndpoint.touched)" [class.valid]="targetEndpoint.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
|
||||||
|
<input type="text" id="destination_url" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.endpoint" size="20" name="endpointUrl" #targetEndpoint="ngModel" required (keyup)="clearPassword($event)">
|
||||||
|
<span class="tooltip-content" *ngIf="targetEndpoint.errors && targetEndpoint.errors.required && (targetEndpoint.dirty || targetEndpoint.touched)">
|
||||||
|
{{ 'DESTINATION.URL_IS_REQUIRED' | translate }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="destination_username" class="col-md-4 form-group-label-override">{{ 'DESTINATION.USERNAME' | translate }}</label>
|
||||||
|
<input type="text" class="col-md-8" id="destination_username" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.username" size="20" name="username" #username="ngModel" (keyup)="clearPassword($event)">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="destination_password" class="col-md-4 form-group-label-override">{{ 'DESTINATION.PASSWORD' | translate }}</label>
|
||||||
|
<input type="password" class="col-md-8" id="destination_password" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.password" size="20" name="password" #password="ngModel" (focus)="clearPassword($event)">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="spin" class="col-md-4"></label>
|
||||||
|
<span class="col-md-8 spinner spinner-inline" [hidden]="!testOngoing"></span>
|
||||||
|
<span [style.color]="!pingStatus ? 'red': ''" class="form-group-label-override">{{ pingTestMessage }}</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-outline" (click)="testConnection()" [disabled]="testOngoing || targetEndpoint.errors">{{ 'DESTINATION.TEST_CONNECTION' | translate }}</button>
|
||||||
|
<button type="button" class="btn btn-outline" (click)="onCancel()" [disabled]="testOngoing">{{ 'BUTTON.CANCEL' | translate }}</button>
|
||||||
|
<button type="submit" class="btn btn-primary" (click)="onSubmit()" [disabled]="testOngoing || targetForm.form.invalid || !editable">{{ 'BUTTON.OK' | translate }}</button>
|
||||||
|
</div>
|
||||||
|
</clr-modal>`;
|
@ -0,0 +1,96 @@
|
|||||||
|
import { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
|
||||||
|
import { FilterComponent } from '../filter/filter.component';
|
||||||
|
|
||||||
|
import { CreateEditEndpointComponent } from '../create-edit-endpoint/create-edit-endpoint.component';
|
||||||
|
import { InlineAlertComponent } from '../inline-alert/inline-alert.component';
|
||||||
|
import { ErrorHandler } from '../error-handler/error-handler';
|
||||||
|
import { Endpoint } from '../service/interface';
|
||||||
|
import { EndpointService, EndpointDefaultService } from '../service/endpoint.service';
|
||||||
|
import { IServiceConfig, SERVICE_CONFIG } from '../service.config';
|
||||||
|
describe('CreateEditEndpointComponent (inline template)', () => {
|
||||||
|
|
||||||
|
let mockData: Endpoint = {
|
||||||
|
"id": 1,
|
||||||
|
"endpoint": "https://10.117.4.151",
|
||||||
|
"name": "target_01",
|
||||||
|
"username": "admin",
|
||||||
|
"password": "",
|
||||||
|
"type": 0
|
||||||
|
};
|
||||||
|
|
||||||
|
let comp: CreateEditEndpointComponent;
|
||||||
|
let fixture: ComponentFixture<CreateEditEndpointComponent>;
|
||||||
|
let de: DebugElement;
|
||||||
|
let el: HTMLElement;
|
||||||
|
|
||||||
|
let config: IServiceConfig = {
|
||||||
|
systemInfoEndpoint: '/api/endpoints/testing'
|
||||||
|
};
|
||||||
|
|
||||||
|
let endpointService: EndpointService;
|
||||||
|
|
||||||
|
let spy: jasmine.Spy;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ SharedModule ],
|
||||||
|
declarations: [
|
||||||
|
FilterComponent,
|
||||||
|
CreateEditEndpointComponent,
|
||||||
|
InlineAlertComponent ],
|
||||||
|
providers: [
|
||||||
|
ErrorHandler,
|
||||||
|
{ provide: SERVICE_CONFIG, useValue: config },
|
||||||
|
{ provide: EndpointService, useClass: EndpointDefaultService },
|
||||||
|
{ provide: TranslateService, useClass: TranslateService}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(()=>{
|
||||||
|
fixture = TestBed.createComponent(CreateEditEndpointComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
|
||||||
|
endpointService = fixture.debugElement.injector.get(EndpointService);
|
||||||
|
spy = spyOn(endpointService, 'getEndpoint').and.returnValue(Promise.resolve(mockData));
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(comp).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get endpoint be called', async(()=>{
|
||||||
|
fixture.detectChanges();
|
||||||
|
comp.openCreateEditTarget(true, 1);
|
||||||
|
comp.createEditDestinationOpened = false;
|
||||||
|
fixture.whenStable().then(()=>{
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(spy.calls.any()).toBeTruthy();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should get endpoint to open modal', async(()=>{
|
||||||
|
fixture.detectChanges();
|
||||||
|
comp.openCreateEditTarget(true, 1);
|
||||||
|
comp.createEditDestinationOpened = false;
|
||||||
|
fixture.whenStable().then(()=>{
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(comp.target.name).toEqual('target_01');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should endpoint be initialized', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(config.systemInfoEndpoint).toEqual('/api/endpoints/testing');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,301 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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, Output, EventEmitter, ViewChild, AfterViewChecked } from '@angular/core';
|
||||||
|
import { NgForm } from '@angular/forms';
|
||||||
|
|
||||||
|
import { EndpointService } from '../service/endpoint.service';
|
||||||
|
import { ErrorHandler } from '../error-handler/index';
|
||||||
|
import { ActionType } from '../shared/shared.const';
|
||||||
|
|
||||||
|
import { InlineAlertComponent } from '../inline-alert/inline-alert.component';
|
||||||
|
|
||||||
|
import { Endpoint } from '../service/interface';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { CREATE_EDIT_ENDPOINT_STYLE } from './create-edit-endpoint.component.css';
|
||||||
|
import { CREATE_EDIT_ENDPOINT_TEMPLATE } from './create-edit-endpoint.component.html';
|
||||||
|
|
||||||
|
|
||||||
|
import { toPromise } from '../utils';
|
||||||
|
|
||||||
|
const FAKE_PASSWORD = 'rjGcfuRu';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'create-edit-endpoint',
|
||||||
|
template: CREATE_EDIT_ENDPOINT_TEMPLATE,
|
||||||
|
styles: [ CREATE_EDIT_ENDPOINT_STYLE ]
|
||||||
|
})
|
||||||
|
export class CreateEditEndpointComponent implements AfterViewChecked {
|
||||||
|
|
||||||
|
modalTitle: string;
|
||||||
|
createEditDestinationOpened: boolean;
|
||||||
|
|
||||||
|
editable: boolean;
|
||||||
|
|
||||||
|
testOngoing: boolean;
|
||||||
|
pingTestMessage: string;
|
||||||
|
pingStatus: boolean;
|
||||||
|
|
||||||
|
actionType: ActionType;
|
||||||
|
|
||||||
|
target: Endpoint = Object.assign({}, this.initEndpoint);
|
||||||
|
initVal: Endpoint = Object.assign({}, this.initEndpoint);
|
||||||
|
|
||||||
|
targetForm: NgForm;
|
||||||
|
|
||||||
|
staticBackdrop: boolean = true;
|
||||||
|
closable: boolean = false;
|
||||||
|
|
||||||
|
@ViewChild('targetForm')
|
||||||
|
currentForm: NgForm;
|
||||||
|
|
||||||
|
hasChanged: boolean;
|
||||||
|
|
||||||
|
endpointHasChanged: boolean;
|
||||||
|
targetNameHasChanged: boolean;
|
||||||
|
|
||||||
|
@ViewChild(InlineAlertComponent)
|
||||||
|
inlineAlert: InlineAlertComponent;
|
||||||
|
|
||||||
|
@Output() reload = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
|
||||||
|
get initEndpoint(): Endpoint {
|
||||||
|
return {
|
||||||
|
endpoint: "",
|
||||||
|
name: "",
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
type: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private endpointService: EndpointService,
|
||||||
|
private errorHandler: ErrorHandler,
|
||||||
|
private translateService: TranslateService) {}
|
||||||
|
|
||||||
|
openCreateEditTarget(editable: boolean, targetId?: number) {
|
||||||
|
|
||||||
|
this.target = Object.assign({}, this.initEndpoint);
|
||||||
|
this.editable = editable;
|
||||||
|
this.createEditDestinationOpened = true;
|
||||||
|
this.hasChanged = false;
|
||||||
|
this.endpointHasChanged = false;
|
||||||
|
this.targetNameHasChanged = false;
|
||||||
|
|
||||||
|
this.pingTestMessage = '';
|
||||||
|
this.pingStatus = true;
|
||||||
|
this.testOngoing = false;
|
||||||
|
|
||||||
|
if(targetId) {
|
||||||
|
this.actionType = ActionType.EDIT;
|
||||||
|
this.translateService.get('DESTINATION.TITLE_EDIT').subscribe(res=>this.modalTitle=res);
|
||||||
|
toPromise<Endpoint>(this.endpointService
|
||||||
|
.getEndpoint(targetId))
|
||||||
|
.then(
|
||||||
|
target=>{
|
||||||
|
this.target = target;
|
||||||
|
this.initVal.name = this.target.name;
|
||||||
|
this.initVal.endpoint = this.target.endpoint;
|
||||||
|
this.initVal.username = this.target.username;
|
||||||
|
this.initVal.password = FAKE_PASSWORD;
|
||||||
|
this.target.password = this.initVal.password;
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error=>this.errorHandler.error(error));
|
||||||
|
} else {
|
||||||
|
this.actionType = ActionType.ADD_NEW;
|
||||||
|
this.translateService.get('DESTINATION.TITLE_ADD').subscribe(res=>this.modalTitle=res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testConnection() {
|
||||||
|
this.translateService.get('DESTINATION.TESTING_CONNECTION').subscribe(res=>this.pingTestMessage=res);
|
||||||
|
this.pingStatus = true;
|
||||||
|
this.testOngoing = !this.testOngoing;
|
||||||
|
|
||||||
|
let payload: Endpoint = Object.assign({}, this.initEndpoint);;
|
||||||
|
if(this.endpointHasChanged) {
|
||||||
|
payload.endpoint = this.target.endpoint;
|
||||||
|
payload.username = this.target.username;
|
||||||
|
payload.password = this.target.password;
|
||||||
|
} else {
|
||||||
|
payload.id = this.target.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
toPromise<Endpoint>(this.endpointService
|
||||||
|
.pingEndpoint(payload))
|
||||||
|
.then(
|
||||||
|
response=>{
|
||||||
|
this.pingStatus = true;
|
||||||
|
this.translateService.get('DESTINATION.TEST_CONNECTION_SUCCESS').subscribe(res=>this.pingTestMessage=res);
|
||||||
|
this.testOngoing = !this.testOngoing;
|
||||||
|
}).catch(
|
||||||
|
error=>{
|
||||||
|
this.pingStatus = false;
|
||||||
|
this.translateService.get('DESTINATION.TEST_CONNECTION_FAILURE').subscribe(res=>this.pingTestMessage=res);
|
||||||
|
this.testOngoing = !this.testOngoing;
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changedTargetName($event: any) {
|
||||||
|
if(this.editable) {
|
||||||
|
this.targetNameHasChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearPassword($event: any) {
|
||||||
|
if(this.editable) {
|
||||||
|
this.target.password = '';
|
||||||
|
this.endpointHasChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
switch(this.actionType) {
|
||||||
|
case ActionType.ADD_NEW:
|
||||||
|
toPromise<number>(this.endpointService
|
||||||
|
.createEndpoint(this.target))
|
||||||
|
.then(
|
||||||
|
response=>{
|
||||||
|
this.errorHandler.info('DESTINATION.CREATED_SUCCESS');
|
||||||
|
this.createEditDestinationOpened = false;
|
||||||
|
this.reload.emit(true);
|
||||||
|
})
|
||||||
|
.catch(
|
||||||
|
error=>{
|
||||||
|
let errorMessageKey = '';
|
||||||
|
switch(error.status) {
|
||||||
|
case 409:
|
||||||
|
errorMessageKey = 'DESTINATION.CONFLICT_NAME';
|
||||||
|
break;
|
||||||
|
case 400:
|
||||||
|
errorMessageKey = 'DESTINATION.INVALID_NAME';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorMessageKey = 'UNKNOWN_ERROR';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.translateService
|
||||||
|
.get(errorMessageKey)
|
||||||
|
.subscribe(res=>{
|
||||||
|
// if(this.messageHandlerService.isAppLevel(error)) {
|
||||||
|
// this.messageHandlerService.handleError(error);
|
||||||
|
// this.createEditDestinationOpened = false;
|
||||||
|
// } else {
|
||||||
|
// this.inlineAlert.showInlineError(res);
|
||||||
|
// }
|
||||||
|
this.errorHandler.error(res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case ActionType.EDIT:
|
||||||
|
if(!(this.targetNameHasChanged || this.endpointHasChanged)) {
|
||||||
|
this.createEditDestinationOpened = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let payload: Endpoint = Object.assign({}, this.initEndpoint);
|
||||||
|
if(this.targetNameHasChanged) {
|
||||||
|
payload.name = this.target.name;
|
||||||
|
}
|
||||||
|
if (this.endpointHasChanged) {
|
||||||
|
payload.endpoint = this.target.endpoint;
|
||||||
|
payload.username = this.target.username;
|
||||||
|
payload.password = this.target.password;
|
||||||
|
delete payload.name;
|
||||||
|
}
|
||||||
|
toPromise<number>(this.endpointService
|
||||||
|
.updateEndpoint(this.target.id, payload))
|
||||||
|
.then(
|
||||||
|
response=>{
|
||||||
|
this.errorHandler.info('DESTINATION.UPDATED_SUCCESS');
|
||||||
|
this.createEditDestinationOpened = false;
|
||||||
|
this.reload.emit(true);
|
||||||
|
})
|
||||||
|
.catch(
|
||||||
|
error=>{
|
||||||
|
let errorMessageKey = '';
|
||||||
|
switch(error.status) {
|
||||||
|
case 409:this
|
||||||
|
errorMessageKey = 'DESTINATION.CONFLICT_NAME';
|
||||||
|
break;
|
||||||
|
case 400:
|
||||||
|
errorMessageKey = 'DESTINATION.INVALID_NAME';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorMessageKey = 'UNKNOWN_ERROR';
|
||||||
|
}
|
||||||
|
this.translateService
|
||||||
|
.get(errorMessageKey)
|
||||||
|
.subscribe(res=>{
|
||||||
|
// if(this.messageHandlerService.isAppLevel(error)) {
|
||||||
|
// this.messageHandlerService.handleError(error);
|
||||||
|
// this.createEditDestinationOpened = false;
|
||||||
|
// } else {
|
||||||
|
// this.inlineAlert.showInlineError(res);
|
||||||
|
// }
|
||||||
|
this.errorHandler.error(res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel() {
|
||||||
|
if(this.hasChanged) {
|
||||||
|
this.inlineAlert.showInlineConfirmation({message: 'ALERT.FORM_CHANGE_CONFIRMATION'});
|
||||||
|
} else {
|
||||||
|
this.createEditDestinationOpened = false;
|
||||||
|
if(this.targetForm)
|
||||||
|
this.targetForm.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmCancel(confirmed: boolean) {
|
||||||
|
this.createEditDestinationOpened = false;
|
||||||
|
this.inlineAlert.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewChecked(): void {
|
||||||
|
this.targetForm = this.currentForm;
|
||||||
|
if(this.targetForm) {
|
||||||
|
let comparison: {[key: string]: string} = {
|
||||||
|
targetName: this.initVal.name,
|
||||||
|
endpointUrl: this.initVal.endpoint,
|
||||||
|
username: this.initVal.username,
|
||||||
|
password: this.initVal.password
|
||||||
|
};
|
||||||
|
this.targetForm.valueChanges.subscribe(data=>{
|
||||||
|
for(let key in data) {
|
||||||
|
let current = data[key];
|
||||||
|
let origin: string = comparison[key];
|
||||||
|
if(((this.actionType === ActionType.EDIT && this.editable && !current) || current) &&
|
||||||
|
current !== origin) {
|
||||||
|
this.hasChanged = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
this.hasChanged = false;
|
||||||
|
this.inlineAlert.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
7
src/ui_ng/lib/src/create-edit-endpoint/index.ts
Normal file
7
src/ui_ng/lib/src/create-edit-endpoint/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Type } from '@angular/core';
|
||||||
|
import { CreateEditEndpointComponent } from './create-edit-endpoint.component';
|
||||||
|
|
||||||
|
|
||||||
|
export const CREATE_EDIT_ENDPOINT_DIRECTIVES: Type<any>[] = [
|
||||||
|
CreateEditEndpointComponent
|
||||||
|
];
|
10
src/ui_ng/lib/src/endpoint/endpoint.component.css.ts
Normal file
10
src/ui_ng/lib/src/endpoint/endpoint.component.css.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export const ENDPOINT_STYLE: string = `
|
||||||
|
.option-left {
|
||||||
|
padding-left: 16px;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
.option-right {
|
||||||
|
padding-right: 16px;
|
||||||
|
margin-top: 36px;
|
||||||
|
}
|
||||||
|
`;
|
36
src/ui_ng/lib/src/endpoint/endpoint.component.html.ts
Normal file
36
src/ui_ng/lib/src/endpoint/endpoint.component.html.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export const ENDPOINT_TEMPLATE: string = `
|
||||||
|
<confirmation-dialog #confirmationDialog (confirmAction)="confirmDeletion($event)" (cancelAction)="cancelDeletion($event)"></confirmation-dialog>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
|
<div class="row flex-items-xs-between">
|
||||||
|
<div class="flex-items-xs-middle option-left">
|
||||||
|
<button class="btn btn-link" (click)="openModal()"><clr-icon shape="add"></clr-icon> {{'DESTINATION.ENDPOINT' | translate}}</button>
|
||||||
|
<create-edit-endpoint (reload)="reload($event)"></create-edit-endpoint>
|
||||||
|
</div>
|
||||||
|
<div class="flex-items-xs-middle option-right">
|
||||||
|
<hbr-filter filterPlaceholder='{{"REPLICATION.FILTER_TARGETS_PLACEHOLDER" | translate}}' (filter)="doSearchTargets($event)" [currentValue]="targetName"></hbr-filter>
|
||||||
|
<a href="javascript:void(0)" (click)="refreshTargets()">
|
||||||
|
<clr-icon shape="refresh"></clr-icon>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
|
<clr-datagrid>
|
||||||
|
<clr-dg-column>{{'DESTINATION.NAME' | translate}}</clr-dg-column>
|
||||||
|
<clr-dg-column>{{'DESTINATION.URL' | translate}}</clr-dg-column>
|
||||||
|
<clr-dg-column>{{'DESTINATION.CREATION_TIME' | translate}}</clr-dg-column>
|
||||||
|
<clr-dg-row *clrDgItems="let t of targets" [clrDgItem]='t'>
|
||||||
|
<clr-dg-action-overflow>
|
||||||
|
<button class="action-item" (click)="editTarget(t)">{{'DESTINATION.TITLE_EDIT' | translate}}</button>
|
||||||
|
<button class="action-item" (click)="deleteTarget(t)">{{'DESTINATION.DELETE' | translate}}</button>
|
||||||
|
</clr-dg-action-overflow>
|
||||||
|
<clr-dg-cell>{{t.name}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>{{t.endpoint}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>{{t.creation_time | date: 'short'}}</clr-dg-cell>
|
||||||
|
</clr-dg-row>
|
||||||
|
<clr-dg-footer>{{ (targets ? targets.length : 0) }} {{'DESTINATION.ITEMS' | translate}}</clr-dg-footer>
|
||||||
|
</clr-datagrid>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
133
src/ui_ng/lib/src/endpoint/endpoint.component.spec.ts
Normal file
133
src/ui_ng/lib/src/endpoint/endpoint.component.spec.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
import { EndpointComponent } from './endpoint.component';
|
||||||
|
import { FilterComponent } from '../filter/filter.component';
|
||||||
|
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
|
||||||
|
import { CreateEditEndpointComponent } from '../create-edit-endpoint/create-edit-endpoint.component';
|
||||||
|
import { InlineAlertComponent } from '../inline-alert/inline-alert.component';
|
||||||
|
import { ErrorHandler } from '../error-handler/error-handler';
|
||||||
|
import { Endpoint } from '../service/interface';
|
||||||
|
import { EndpointService, EndpointDefaultService } from '../service/endpoint.service';
|
||||||
|
import { IServiceConfig, SERVICE_CONFIG } from '../service.config';
|
||||||
|
describe('EndpointComponent (inline template)', () => {
|
||||||
|
|
||||||
|
let mockData: Endpoint[] = [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"endpoint": "https://10.117.4.151",
|
||||||
|
"name": "target_01",
|
||||||
|
"username": "admin",
|
||||||
|
"password": "",
|
||||||
|
"type": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"endpoint": "https://10.117.5.142",
|
||||||
|
"name": "target_02",
|
||||||
|
"username": "AAA",
|
||||||
|
"password": "",
|
||||||
|
"type": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"endpoint": "https://101.1.11.111",
|
||||||
|
"name": "target_03",
|
||||||
|
"username": "admin",
|
||||||
|
"password": "",
|
||||||
|
"type": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"endpoint": "http://4.4.4.4",
|
||||||
|
"name": "target_04",
|
||||||
|
"username": "",
|
||||||
|
"password": "",
|
||||||
|
"type": 0
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let mockOne: Endpoint = {
|
||||||
|
"id": 1,
|
||||||
|
"endpoint": "https://10.117.4.151",
|
||||||
|
"name": "target_01",
|
||||||
|
"username": "admin",
|
||||||
|
"password": "",
|
||||||
|
"type": 0
|
||||||
|
};
|
||||||
|
|
||||||
|
let comp: EndpointComponent;
|
||||||
|
let fixture: ComponentFixture<EndpointComponent>;
|
||||||
|
let de: DebugElement;
|
||||||
|
let el: HTMLElement;
|
||||||
|
|
||||||
|
let config: IServiceConfig = {
|
||||||
|
systemInfoEndpoint: '/api/endpoints/testing'
|
||||||
|
};
|
||||||
|
|
||||||
|
let endpointService: EndpointService;
|
||||||
|
let spy: jasmine.Spy;
|
||||||
|
let spyOnRules: jasmine.Spy;
|
||||||
|
let spyOne: jasmine.Spy;
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ SharedModule ],
|
||||||
|
declarations: [
|
||||||
|
FilterComponent,
|
||||||
|
ConfirmationDialogComponent,
|
||||||
|
CreateEditEndpointComponent,
|
||||||
|
InlineAlertComponent,
|
||||||
|
EndpointComponent ],
|
||||||
|
providers: [
|
||||||
|
ErrorHandler,
|
||||||
|
{ provide: SERVICE_CONFIG, useValue: config },
|
||||||
|
{ provide: EndpointService, useClass: EndpointDefaultService }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(()=>{
|
||||||
|
fixture = TestBed.createComponent(EndpointComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
|
||||||
|
endpointService = fixture.debugElement.injector.get(EndpointService);
|
||||||
|
|
||||||
|
spy = spyOn(endpointService, 'getEndpoints').and.returnValues(Promise.resolve(mockData));
|
||||||
|
spyOnRules = spyOn(endpointService, 'getEndpointWithReplicationRules').and.returnValue([]);
|
||||||
|
spyOne = spyOn(endpointService, 'getEndpoint').and.returnValue(Promise.resolve(mockOne));
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrieve endpoint data', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(spy.calls.any()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should endpoint be initialized', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(config.systemInfoEndpoint).toEqual('/api/endpoints/testing');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open create endpoint modal', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
comp.editTarget(mockOne);
|
||||||
|
fixture.whenStable().then(()=>{
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(comp.target.name).toEqual('target_01');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should filter endpoints by keyword', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(()=>{
|
||||||
|
fixture.detectChanges();
|
||||||
|
comp.doSearchTargets('target_02');
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(comp.targets.length).toEqual(1);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
181
src/ui_ng/lib/src/endpoint/endpoint.component.ts
Normal file
181
src/ui_ng/lib/src/endpoint/endpoint.component.ts
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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, OnInit, ViewChild, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { Endpoint, ReplicationRule } from '../service/interface';
|
||||||
|
import { EndpointService } from '../service/endpoint.service';
|
||||||
|
import { ErrorHandler } from '../error-handler/index';
|
||||||
|
|
||||||
|
import { ConfirmationMessage } from '../confirmation-dialog/confirmation-message';
|
||||||
|
import { ConfirmationAcknowledgement } from '../confirmation-dialog/confirmation-state-message';
|
||||||
|
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
|
||||||
|
|
||||||
|
import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../shared/shared.const';
|
||||||
|
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
|
||||||
|
import { CreateEditEndpointComponent } from '../create-edit-endpoint/create-edit-endpoint.component';
|
||||||
|
|
||||||
|
import { ENDPOINT_STYLE } from './endpoint.component.css';
|
||||||
|
import { ENDPOINT_TEMPLATE } from './endpoint.component.html';
|
||||||
|
|
||||||
|
import { toPromise } from '../utils';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'hbr-endpoint',
|
||||||
|
template: ENDPOINT_TEMPLATE,
|
||||||
|
styles: [ ENDPOINT_STYLE ],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class EndpointComponent implements OnInit {
|
||||||
|
|
||||||
|
@ViewChild(CreateEditEndpointComponent)
|
||||||
|
createEditEndpointComponent: CreateEditEndpointComponent;
|
||||||
|
|
||||||
|
|
||||||
|
@ViewChild('confirmationDialog')
|
||||||
|
confirmationDialogComponent: ConfirmationDialogComponent;
|
||||||
|
|
||||||
|
targets: Endpoint[];
|
||||||
|
target: Endpoint;
|
||||||
|
|
||||||
|
targetName: string;
|
||||||
|
subscription: Subscription;
|
||||||
|
|
||||||
|
get initEndpoint(): Endpoint {
|
||||||
|
return {
|
||||||
|
endpoint: "",
|
||||||
|
name: "",
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
type: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private endpointService: EndpointService,
|
||||||
|
private errorHandler: ErrorHandler,
|
||||||
|
private ref: ChangeDetectorRef) {
|
||||||
|
let hnd = setInterval(()=>ref.markForCheck(), 100);
|
||||||
|
setTimeout(()=>clearInterval(hnd), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmDeletion(message: ConfirmationAcknowledgement) {
|
||||||
|
if (message &&
|
||||||
|
message.source === ConfirmationTargets.TARGET &&
|
||||||
|
message.state === ConfirmationState.CONFIRMED) {
|
||||||
|
|
||||||
|
let targetId = message.data;
|
||||||
|
toPromise<number>(this.endpointService
|
||||||
|
.deleteEndpoint(targetId))
|
||||||
|
.then(
|
||||||
|
response => {
|
||||||
|
this.errorHandler.error('DESTINATION.DELETED_SUCCESS');
|
||||||
|
this.reload(true);
|
||||||
|
}).catch(
|
||||||
|
error => {
|
||||||
|
if(error && error.status === 412) {
|
||||||
|
this.errorHandler.error('DESTINATION.FAILED_TO_DELETE_TARGET_IN_USED');
|
||||||
|
} else {
|
||||||
|
this.errorHandler.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelDeletion(message: ConfirmationAcknowledgement) {
|
||||||
|
console.log('Received message from cancelAction:' + JSON.stringify(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.targetName = '';
|
||||||
|
this.retrieve('');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (this.subscription) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retrieve(targetName: string): void {
|
||||||
|
toPromise<Endpoint[]>(this.endpointService
|
||||||
|
.getEndpoints(targetName))
|
||||||
|
.then(
|
||||||
|
targets => {
|
||||||
|
this.targets = targets || [];
|
||||||
|
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
|
||||||
|
setTimeout(()=>clearInterval(hnd), 1000);
|
||||||
|
}).catch(error => this.errorHandler.error(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
doSearchTargets(targetName: string) {
|
||||||
|
this.targetName = targetName;
|
||||||
|
this.retrieve(targetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshTargets() {
|
||||||
|
this.retrieve('');
|
||||||
|
}
|
||||||
|
|
||||||
|
reload($event: any) {
|
||||||
|
this.targetName = '';
|
||||||
|
this.retrieve('');
|
||||||
|
}
|
||||||
|
|
||||||
|
openModal() {
|
||||||
|
this.createEditEndpointComponent.openCreateEditTarget(true);
|
||||||
|
this.target = this.initEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
editTarget(target: Endpoint) {
|
||||||
|
if (target) {
|
||||||
|
let editable = true;
|
||||||
|
|
||||||
|
toPromise<ReplicationRule[]>(this.endpointService
|
||||||
|
.getEndpointWithReplicationRules(target.id))
|
||||||
|
.then(
|
||||||
|
rules=>{
|
||||||
|
if(rules && rules.length > 0) {
|
||||||
|
for(let i = 0; i < rules.length; i++){
|
||||||
|
let p: ReplicationRule = rules[i];
|
||||||
|
if(p.enabled === 1) {
|
||||||
|
editable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.createEditEndpointComponent.openCreateEditTarget(editable, +target.id);
|
||||||
|
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
|
||||||
|
setTimeout(()=>clearInterval(hnd), 1000);
|
||||||
|
})
|
||||||
|
.catch(error=>this.errorHandler.error(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTarget(target: Endpoint) {
|
||||||
|
console.log('Endpoint:' + JSON.stringify(target));
|
||||||
|
if (target) {
|
||||||
|
let targetId = target.id;
|
||||||
|
let deletionMessage = new ConfirmationMessage(
|
||||||
|
'REPLICATION.DELETION_TITLE_TARGET',
|
||||||
|
'REPLICATION.DELETION_SUMMARY_TARGET',
|
||||||
|
target.name,
|
||||||
|
target.id,
|
||||||
|
ConfirmationTargets.TARGET,
|
||||||
|
ConfirmationButtons.DELETE_CANCEL);
|
||||||
|
this.confirmationDialogComponent.open(deletionMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/ui_ng/lib/src/endpoint/index.ts
Normal file
7
src/ui_ng/lib/src/endpoint/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Type } from '@angular/core';
|
||||||
|
import { EndpointComponent } from './endpoint.component';
|
||||||
|
|
||||||
|
|
||||||
|
export const ENDPOINT_DIRECTIVES: Type<any>[] = [
|
||||||
|
EndpointComponent
|
||||||
|
];
|
@ -2,7 +2,14 @@ import { NgModule, ModuleWithProviders, Provider, APP_INITIALIZER, Inject } from
|
|||||||
|
|
||||||
import { LOG_DIRECTIVES } from './log/index';
|
import { LOG_DIRECTIVES } from './log/index';
|
||||||
import { FILTER_DIRECTIVES } from './filter/index';
|
import { FILTER_DIRECTIVES } from './filter/index';
|
||||||
|
import { ENDPOINT_DIRECTIVES } from './endpoint/index';
|
||||||
|
import { CREATE_EDIT_ENDPOINT_DIRECTIVES } from './create-edit-endpoint/index';
|
||||||
|
|
||||||
import { SERVICE_CONFIG, IServiceConfig } from './service.config';
|
import { SERVICE_CONFIG, IServiceConfig } from './service.config';
|
||||||
|
|
||||||
|
import { CONFIRMATION_DIALOG_DIRECTIVES } from './confirmation-dialog/index';
|
||||||
|
import { INLINE_ALERT_DIRECTIVES } from './inline-alert/index';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AccessLogService,
|
AccessLogService,
|
||||||
AccessLogDefaultService,
|
AccessLogDefaultService,
|
||||||
@ -110,12 +117,21 @@ export function initConfig(translateService: TranslateService, config: IServiceC
|
|||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
LOG_DIRECTIVES,
|
LOG_DIRECTIVES,
|
||||||
FILTER_DIRECTIVES
|
FILTER_DIRECTIVES,
|
||||||
|
ENDPOINT_DIRECTIVES,
|
||||||
|
CREATE_EDIT_ENDPOINT_DIRECTIVES,
|
||||||
|
CONFIRMATION_DIALOG_DIRECTIVES,
|
||||||
|
INLINE_ALERT_DIRECTIVES
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
LOG_DIRECTIVES,
|
LOG_DIRECTIVES,
|
||||||
FILTER_DIRECTIVES
|
FILTER_DIRECTIVES,
|
||||||
]
|
ENDPOINT_DIRECTIVES,
|
||||||
|
CREATE_EDIT_ENDPOINT_DIRECTIVES,
|
||||||
|
CONFIRMATION_DIALOG_DIRECTIVES,
|
||||||
|
INLINE_ALERT_DIRECTIVES
|
||||||
|
],
|
||||||
|
providers: []
|
||||||
})
|
})
|
||||||
|
|
||||||
export class HarborLibraryModule {
|
export class HarborLibraryModule {
|
||||||
@ -156,4 +172,4 @@ export class HarborLibraryModule {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,4 +4,5 @@ export * from './service/index';
|
|||||||
export * from './error-handler/index';
|
export * from './error-handler/index';
|
||||||
//export * from './utils';
|
//export * from './utils';
|
||||||
export * from './log/index';
|
export * from './log/index';
|
||||||
export * from './filter/index';
|
export * from './filter/index';
|
||||||
|
export * from './endpoint/index';
|
7
src/ui_ng/lib/src/inline-alert/index.ts
Normal file
7
src/ui_ng/lib/src/inline-alert/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Type } from '@angular/core';
|
||||||
|
|
||||||
|
import { InlineAlertComponent } from './inline-alert.component';
|
||||||
|
|
||||||
|
export const INLINE_ALERT_DIRECTIVES: Type<any>[] = [
|
||||||
|
InlineAlertComponent
|
||||||
|
];
|
10
src/ui_ng/lib/src/inline-alert/inline-alert.component.css.ts
Normal file
10
src/ui_ng/lib/src/inline-alert/inline-alert.component.css.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export const INLINE_ALERT_STYLE: string = `
|
||||||
|
.alert-text-blink {
|
||||||
|
color: red;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
.alert-btn-link {
|
||||||
|
padding: 0px !important;
|
||||||
|
min-width: 30px !important;
|
||||||
|
}
|
||||||
|
`;
|
@ -0,0 +1,13 @@
|
|||||||
|
export const INLINE_ALERT_TEMPLATE: string = `
|
||||||
|
<clr-alert [clrAlertType]="inlineAlertType" [clrAlertClosable]="inlineAlertClosable" [(clrAlertClosed)]="alertClose" [clrAlertAppLevel]="useAppLevelStyle">
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text" [class.alert-text-blink]="blinking">
|
||||||
|
{{errorMessage}}
|
||||||
|
</span>
|
||||||
|
<div class="alert-actions" *ngIf="showCancelAction">
|
||||||
|
<button class="btn btn-sm btn-link alert-btn-link" (click)="close()">{{'BUTTON.NO' | translate}}</button>
|
||||||
|
<button class="btn btn-sm btn-link alert-btn-link" (click)="confirmCancel()">{{'BUTTON.YES' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</clr-alert>
|
||||||
|
`;
|
99
src/ui_ng/lib/src/inline-alert/inline-alert.component.ts
Normal file
99
src/ui_ng/lib/src/inline-alert/inline-alert.component.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { errorHandler } from '../shared/shared.utils';
|
||||||
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
import { Subscription } from "rxjs";
|
||||||
|
|
||||||
|
import { INLINE_ALERT_STYLE } from './inline-alert.component.css';
|
||||||
|
import { INLINE_ALERT_TEMPLATE } from './inline-alert.component.html';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'inline-alert',
|
||||||
|
template: INLINE_ALERT_TEMPLATE,
|
||||||
|
styles: [ INLINE_ALERT_STYLE ]
|
||||||
|
})
|
||||||
|
export class InlineAlertComponent {
|
||||||
|
inlineAlertType: string = 'alert-danger';
|
||||||
|
inlineAlertClosable: boolean = false;
|
||||||
|
alertClose: boolean = true;
|
||||||
|
displayedText: string = "";
|
||||||
|
showCancelAction: boolean = false;
|
||||||
|
useAppLevelStyle: boolean = false;
|
||||||
|
timer: Subscription | null = null;
|
||||||
|
count: number = 0;
|
||||||
|
blinking: boolean = false;
|
||||||
|
|
||||||
|
@Output() confirmEvt = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
constructor(private translate: TranslateService) { }
|
||||||
|
|
||||||
|
public get errorMessage(): string {
|
||||||
|
return this.displayedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show error message inline
|
||||||
|
public showInlineError(error: any): void {
|
||||||
|
this.displayedText = errorHandler(error);
|
||||||
|
if (this.displayedText) {
|
||||||
|
this.translate.get(this.displayedText).subscribe((res: string) => this.displayedText = res);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inlineAlertType = 'alert-danger';
|
||||||
|
this.showCancelAction = false;
|
||||||
|
this.inlineAlertClosable = true;
|
||||||
|
this.alertClose = false;
|
||||||
|
this.useAppLevelStyle = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show confirmation info with action button
|
||||||
|
public showInlineConfirmation(warning: any): void {
|
||||||
|
this.displayedText = "";
|
||||||
|
if (warning && warning.message) {
|
||||||
|
this.translate.get(warning.message).subscribe((res: string) => this.displayedText = res);
|
||||||
|
}
|
||||||
|
this.inlineAlertType = 'alert-warning';
|
||||||
|
this.showCancelAction = true;
|
||||||
|
this.inlineAlertClosable = false;
|
||||||
|
this.alertClose = false;
|
||||||
|
this.useAppLevelStyle = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show inline sccess info
|
||||||
|
public showInlineSuccess(info: any): void {
|
||||||
|
this.displayedText = "";
|
||||||
|
if (info && info.message) {
|
||||||
|
this.translate.get(info.message).subscribe((res: string) => this.displayedText = res);
|
||||||
|
}
|
||||||
|
this.inlineAlertType = 'alert-success';
|
||||||
|
this.showCancelAction = false;
|
||||||
|
this.inlineAlertClosable = true;
|
||||||
|
this.alertClose = false;
|
||||||
|
this.useAppLevelStyle = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Close alert
|
||||||
|
public close(): void {
|
||||||
|
this.alertClose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public blink() {
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmCancel(): void {
|
||||||
|
this.confirmEvt.emit(true);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,13 @@
|
|||||||
import { TestBed, inject } from '@angular/core/testing';
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
import { SharedModule } from '../shared/shared.module';
|
||||||
import { EndpointService, EndpointDefaultService } from './endpoint.service';
|
import { EndpointService, EndpointDefaultService } from './endpoint.service';
|
||||||
|
|
||||||
describe('EndpointService', () => {
|
describe('EndpointService', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
SharedModule
|
||||||
|
],
|
||||||
providers: [
|
providers: [
|
||||||
EndpointDefaultService,
|
EndpointDefaultService,
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { RequestQueryParams } from './RequestQueryParams';
|
import { RequestQueryParams } from './RequestQueryParams';
|
||||||
import { Endpoint } from './interface';
|
import { Endpoint, ReplicationRule } from './interface';
|
||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
|
import { Http } from '@angular/http';
|
||||||
import 'rxjs/add/observable/of';
|
import 'rxjs/add/observable/of';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,6 +81,15 @@ export abstract class EndpointService {
|
|||||||
* @memberOf EndpointService
|
* @memberOf EndpointService
|
||||||
*/
|
*/
|
||||||
abstract pingEndpoint(endpoint: Endpoint): Observable<any> | Promise<any> | any;
|
abstract pingEndpoint(endpoint: Endpoint): Observable<any> | Promise<any> | any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check endpoint whether in used with specific replication rule.
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @param {{number | string}} endpointId
|
||||||
|
* @returns {{Observable<any> | any}}
|
||||||
|
*/
|
||||||
|
abstract getEndpointWithReplicationRules(endpointId: number | string): Observable<any> | Promise<any> | any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,28 +101,71 @@ export abstract class EndpointService {
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EndpointDefaultService extends EndpointService {
|
export class EndpointDefaultService extends EndpointService {
|
||||||
|
|
||||||
|
constructor(private http: Http){
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
public getEndpoints(endpointName?: string, queryParams?: RequestQueryParams): Observable<Endpoint[]> | Promise<Endpoint[]> | Endpoint[] {
|
public getEndpoints(endpointName?: string, queryParams?: RequestQueryParams): Observable<Endpoint[]> | Promise<Endpoint[]> | Endpoint[] {
|
||||||
return Observable.of([]);
|
return this.http
|
||||||
|
.get(`/api/targets?name=${endpointName}`)
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.json())
|
||||||
|
.catch(error=>Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEndpoint(endpointId: number | string): Observable<Endpoint> | Promise<Endpoint> | Endpoint {
|
public getEndpoint(endpointId: number | string): Observable<Endpoint> | Promise<Endpoint> | Endpoint {
|
||||||
return Observable.of({});
|
return this.http
|
||||||
|
.get(`/api/targets/${endpointId}`)
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.json() as Endpoint)
|
||||||
|
.catch(error=>Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public createEndpoint(endpoint: Endpoint): Observable<any> | Promise<any> | any {
|
public createEndpoint(endpoint: Endpoint): Observable<any> | Promise<any> | any {
|
||||||
return Observable.of({});
|
return this.http
|
||||||
|
.post(`/api/targets`, JSON.stringify(endpoint))
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.status)
|
||||||
|
.catch(error=>Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateEndpoint(endpointId: number | string, endpoint: Endpoint): Observable<any> | Promise<any> | any {
|
public updateEndpoint(endpointId: number | string, endpoint: Endpoint): Observable<any> | Promise<any> | any {
|
||||||
return Observable.of({});
|
return this.http
|
||||||
|
.put(`/api/targets/${endpointId}`, JSON.stringify(endpoint))
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.status)
|
||||||
|
.catch(error=>Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteEndpoint(endpointId: number | string): Observable<any> | Promise<any> | any {
|
public deleteEndpoint(endpointId: number | string): Observable<any> | Promise<any> | any {
|
||||||
return Observable.of({});
|
return this.http
|
||||||
|
.delete(`/api/targets/${endpointId}`)
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.status)
|
||||||
|
.catch(error=>Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public pingEndpoint(endpoint: Endpoint): Observable<any> | Promise<any> | any {
|
public pingEndpoint(endpoint: Endpoint): Observable<any> | Promise<any> | any {
|
||||||
return Observable.of({});
|
if(endpoint.id) {
|
||||||
|
return this.http
|
||||||
|
.post(`/api/targets/${endpoint.id}/ping`, {})
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.status)
|
||||||
|
.catch(error=>Promise.reject(error));
|
||||||
|
}
|
||||||
|
return this.http
|
||||||
|
.post(`/api/targets/ping`, endpoint)
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.status)
|
||||||
|
.catch(error=>Observable.throw(error));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public getEndpointWithReplicationRules(endpointId: number | string): Observable<any> | Promise<any> | any {
|
||||||
|
return this.http
|
||||||
|
.get(`/api/targets/${endpointId}/policies`)
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.json() as ReplicationRule[])
|
||||||
|
.catch(error=>Promise.reject(error));
|
||||||
|
}
|
||||||
|
}
|
@ -72,7 +72,13 @@ export interface Tag extends Base {
|
|||||||
* @interface Endpoint
|
* @interface Endpoint
|
||||||
* @extends {Base}
|
* @extends {Base}
|
||||||
*/
|
*/
|
||||||
export interface Endpoint extends Base { }
|
export interface Endpoint extends Base {
|
||||||
|
endpoint: string;
|
||||||
|
name: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
type: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for replication rule.
|
* Interface for replication rule.
|
||||||
|
@ -114,7 +114,6 @@ export abstract class ReplicationService {
|
|||||||
* @memberOf ReplicationService
|
* @memberOf ReplicationService
|
||||||
*/
|
*/
|
||||||
abstract getJobs(ruleId: number | string, queryParams?: RequestQueryParams): Observable<ReplicationJob[]> | Promise<ReplicationJob[]> | ReplicationJob[];
|
abstract getJobs(ruleId: number | string, queryParams?: RequestQueryParams): Observable<ReplicationJob[]> | Promise<ReplicationJob[]> | ReplicationJob[];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
68
src/ui_ng/lib/src/shared/shared.const.ts
Normal file
68
src/ui_ng/lib/src/shared/shared.const.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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.
|
||||||
|
export const supportedLangs = ['en-us', 'zh-cn', 'es-es'];
|
||||||
|
export const enLang = "en-us";
|
||||||
|
export const languageNames = {
|
||||||
|
"en-us": "English",
|
||||||
|
"zh-cn": "中文简体",
|
||||||
|
"es-es": "Español"
|
||||||
|
};
|
||||||
|
export const enum AlertType {
|
||||||
|
DANGER, WARNING, INFO, SUCCESS
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dismissInterval = 10 * 1000;
|
||||||
|
export const httpStatusCode = {
|
||||||
|
"Unauthorized": 401,
|
||||||
|
"Forbidden": 403
|
||||||
|
};
|
||||||
|
export const enum ConfirmationTargets {
|
||||||
|
EMPTY,
|
||||||
|
PROJECT,
|
||||||
|
PROJECT_MEMBER,
|
||||||
|
USER,
|
||||||
|
POLICY,
|
||||||
|
TOGGLE_CONFIRM,
|
||||||
|
TARGET,
|
||||||
|
REPOSITORY,
|
||||||
|
TAG,
|
||||||
|
CONFIG,
|
||||||
|
CONFIG_ROUTE,
|
||||||
|
CONFIG_TAB
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enum ActionType {
|
||||||
|
ADD_NEW, EDIT
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ListMode = {
|
||||||
|
READONLY: "readonly",
|
||||||
|
FULL: "full"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CommonRoutes = {
|
||||||
|
SIGN_IN: "/sign-in",
|
||||||
|
EMBEDDED_SIGN_IN: "/harbor/sign-in",
|
||||||
|
SIGN_UP: "/sign-in?sign_up=true",
|
||||||
|
EMBEDDED_SIGN_UP: "/harbor/sign-in?sign_up=true",
|
||||||
|
HARBOR_ROOT: "/harbor",
|
||||||
|
HARBOR_DEFAULT: "/harbor/projects"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enum ConfirmationState {
|
||||||
|
NA, CONFIRMED, CANCEL
|
||||||
|
}
|
||||||
|
export const enum ConfirmationButtons {
|
||||||
|
CONFIRM_CANCEL, YES_NO, DELETE_CANCEL, CLOSE
|
||||||
|
}
|
@ -1,14 +1,14 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { HttpModule } from '@angular/http';
|
import { HttpModule, Http } from '@angular/http';
|
||||||
import { ClarityModule } from 'clarity-angular';
|
import { ClarityModule } from 'clarity-angular';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { TranslateModule, TranslateLoader, TranslateService, MissingTranslationHandler } from "@ngx-translate/core";
|
import { TranslateModule, TranslateLoader, TranslateService, MissingTranslationHandler } from "@ngx-translate/core";
|
||||||
import { MyMissingTranslationHandler } from '../i18n/missing-trans.handler';
|
import { MyMissingTranslationHandler } from '../i18n/missing-trans.handler';
|
||||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||||
import { Http } from '@angular/http';
|
|
||||||
import { TranslatorJsonLoader } from '../i18n/local-json.loader';
|
import { TranslatorJsonLoader } from '../i18n/local-json.loader';
|
||||||
|
|
||||||
|
|
||||||
/*export function HttpLoaderFactory(http: Http) {
|
/*export function HttpLoaderFactory(http: Http) {
|
||||||
return new TranslateHttpLoader(http, 'i18n/lang/', '-lang.json');
|
return new TranslateHttpLoader(http, 'i18n/lang/', '-lang.json');
|
||||||
}*/
|
}*/
|
||||||
|
49
src/ui_ng/lib/src/shared/shared.utils.ts
Normal file
49
src/ui_ng/lib/src/shared/shared.utils.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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 { NgForm } from '@angular/forms';
|
||||||
|
import { httpStatusCode, AlertType } from './shared.const';
|
||||||
|
/**
|
||||||
|
* To handle the error message body
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export const errorHandler = function (error: any): string {
|
||||||
|
if (!error) {
|
||||||
|
return "UNKNOWN_ERROR";
|
||||||
|
}
|
||||||
|
if (!(error.statusCode || error.status)) {
|
||||||
|
//treat as string message
|
||||||
|
return '' + error;
|
||||||
|
} else {
|
||||||
|
switch (error.statusCode || error.status) {
|
||||||
|
case 400:
|
||||||
|
return "BAD_REQUEST_ERROR";
|
||||||
|
case 401:
|
||||||
|
return "UNAUTHORIZED_ERROR";
|
||||||
|
case 403:
|
||||||
|
return "FORBIDDEN_ERROR";
|
||||||
|
case 404:
|
||||||
|
return "NOT_FOUND_ERROR";
|
||||||
|
case 412:
|
||||||
|
return "PRECONDITION_FAILED";
|
||||||
|
case 409:
|
||||||
|
return "CONFLICT_ERROR";
|
||||||
|
case 500:
|
||||||
|
return "SERVER_ERROR";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN_ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user