Merge pull request #4134 from pengpengshui/batchDelection

Add username and pwd for target and unselected project name and targe…
This commit is contained in:
pengpengshui 2018-01-26 14:42:17 +08:00 committed by GitHub
commit 72cc56100f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 211 additions and 102 deletions

View File

@ -241,15 +241,16 @@ export class CreateEditEndpointComponent implements AfterViewChecked, OnDestroy
this.onGoing = false;
this.close();
}).catch(error => {
this.onGoing = false;
let errorMessageKey = this.handleErrorMessageKey(error.status);
this.translateService
.get(errorMessageKey)
.subscribe(res => {
this.inlineAlert.showInlineError(res);
this.onGoing = false;
});
}
);
this.forceRefreshView(1000);
}
updateEndpoint() {
@ -295,6 +296,7 @@ export class CreateEditEndpointComponent implements AfterViewChecked, OnDestroy
this.onGoing = false;
}
);
this.forceRefreshView(100);
}
handleErrorMessageKey(status: number): string {

View File

@ -13,14 +13,14 @@ export const LIST_REPLICATION_RULE_TEMPLATE: string = `
<clr-dg-column [clrDgField]="'targets'">{{'REPLICATION.DESTINATION_NAME' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.TRIGGER_MODE' | translate}}</clr-dg-column>
<clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder>
<clr-dg-row *clrDgItems="let p of changedRules" [clrDgItem]="p" [style.backgroundColor]="(projectScope && withReplicationJob && selectedId === p.id) ? '#eee' : ''">
<clr-dg-cell (click)="selectRule(p)">{{p.name}}</clr-dg-cell>
<clr-dg-cell *ngIf="!projectScope" (click)="selectRule(p)">
<a href="javascript:void(0)" (click)="redirectTo(p)">{{p.projects?.length>0 ? p.projects[0].name : ''}}</a>
<clr-dg-row *clrDgItems="let p of changedRules" [clrDgItem]="p" (click)="selectRule(p)" [style.backgroundColor]="(projectScope && withReplicationJob && selectedId === p.id) ? '#eee' : ''">
<clr-dg-cell>{{p.name}}</clr-dg-cell>
<clr-dg-cell *ngIf="!projectScope">
<a href="javascript:void(0)">{{p.projects?.length>0 ? p.projects[0].name : ''}}</a>
</clr-dg-cell>
<clr-dg-cell (click)="selectRule(p)">{{p.description ? p.description : '-'}}</clr-dg-cell>
<clr-dg-cell (click)="selectRule(p)">{{p.targets?.length>0 ? p.targets[0].name : ''}}</clr-dg-cell>
<clr-dg-cell (click)="selectRule(p)">{{p.trigger ? p.trigger.kind : ''}}</clr-dg-cell>
<clr-dg-cell>{{p.description ? p.description : '-'}}</clr-dg-cell>
<clr-dg-cell>{{p.targets?.length>0 ? p.targets[0].name : ''}}</clr-dg-cell>
<clr-dg-cell>{{p.trigger ? p.trigger.kind : ''}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} </span>{{pagination.totalItems }} {{'REPLICATION.ITEMS' | translate}}

View File

@ -187,7 +187,6 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
selectRule(rule: ReplicationRule): void {
this.selectedId = rule.id || '';
this.selectedRow = null;
this.selectOne.emit(rule);
}

View File

@ -31,7 +31,7 @@
"clarity-icons": "^0.10.17",
"clarity-ui": "^0.10.17",
"core-js": "^2.4.1",
"harbor-ui": "0.6.30",
"harbor-ui": "0.6.32",
"intl": "^1.2.5",
"mutationobserver-shim": "^0.3.2",
"ngx-cookie": "^1.0.0",

View File

@ -8,7 +8,7 @@
<label for="create_project_name" class="col-md-3 form-group-label-override required">{{'PROJECT.NAME' | translate}}</label>
<label for="create_project_name" aria-haspopup="true" role="tooltip" [class.invalid]="!isNameValid" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left">
<input type="text" id="create_project_name" [(ngModel)]="project.name"
name="create_project_name" size="255"
name="create_project_name" size="255" style="width: 296px;"
required
pattern="^[a-z0-9]+(?:[._-][a-z0-9]+)*$"
minlength="2"

View File

@ -1,4 +1,4 @@
<clr-modal [(clrModalOpen)]="ismodelOpen">
<clr-modal [(clrModalOpen)]="ismodelOpen" [clrModalClosable]="false">
<h3 class="modal-title">{{'PROJECT.ALL_PROJECTS' | translate}}</h3>
<inline-alert class="modal-title" ></inline-alert>
<div class="modal-body">

View File

@ -17,6 +17,7 @@ import {CreateEditEndpointComponent} from "harbor-ui/src/create-edit-endpoint/cr
const ONE_HOUR_SECONDS: number = 3600;
const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
const FAKE_PASSWORD = 'rjGcfuRu';
@Component ({
selector: 'repliction-rule',
@ -33,11 +34,12 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
weeklySchedule: boolean;
isScheduleOpt: boolean;
isImmediate: boolean = true;
noProjectInfo: string;
noEndpointInfo: boolean;
noProjectInfo: string = "";
noSelectedProject: boolean = true;
noSelectedEndpoint: boolean = true;
filterCount: number = 0;
selectedprojectList: Project[] = [];
triggerNames: string[] = ['Immediate', 'Scheduled', 'Manual'];
triggerNames: string[] = ['Manual', 'Immediate', 'Scheduled'];
scheduleNames: string[] = ['Daily', 'Weekly'];
weekly: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
filterSelect: string[] = ['repository', 'tag'];
@ -50,6 +52,8 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
isRuleNameExist: boolean = false;
isSubmitOver: boolean = false;
nameChecker: Subject<string> = new Subject<string>();
firstEndpointData: { [key: string]: string };
realEndpointData: { [key: string]: string } = this.initEndpointData();
confirmSub: Subscription;
ruleForm: FormGroup;
@ -61,6 +65,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
@ViewChild(CreateEditEndpointComponent)
createEditEndpointComponent: CreateEditEndpointComponent;
baseFilterData(name: string, option: string[], state: boolean) {
return {
name: name,
@ -70,6 +75,13 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
};
}
initEndpointData(): { [key: string]: string } {
return{
userName: "",
password: ""
};
}
constructor(public projectService: ProjectService,
private router: Router,
private fb: FormBuilder,
@ -83,11 +95,14 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
Promise.all([this.repService.getEndpoints(), this.repService.listProjects()])
.then(res => {
if (!res[0]) {
this.noEndpointInfo = true;
this.noSelectedEndpoint = true;
}else {
this.targetList = res[0];
if (!this.policyId) {
this.setTarget([res[0][0]]);
this.realEndpointData.userName = res[0][0].username;
this.realEndpointData.password = FAKE_PASSWORD;
this.firstEndpointData = Object.assign({}, this.realEndpointData);
}
}
if (!res[1]) {
@ -98,6 +113,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
}
if (!this.policyId && this.projectId) {
this.setProject( res[1].filter(rule => rule.project_id === this.projectId));
this.noSelectedProject = false;
}
}
if (!this.policyId) {
@ -148,7 +164,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
}
get isVaild() {
return !(this.isRuleNameExist || this.noProjectInfo || this.noEndpointInfo || this.inProgress || this.isSubmitOver);
return !(this.isRuleNameExist || this.noSelectedProject || this.noSelectedEndpoint || this.inProgress || this.isSubmitOver);
}
createForm() {
@ -169,7 +185,6 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
replicate_existing_image_now: true,
replicate_deletion: false
});
}
updateForm(rule: ReplicationRule): void {
@ -182,7 +197,14 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
replicate_deletion: rule.replicate_deletion
});
this.setProject(rule.projects);
this.noSelectedProject = false;
this.setTarget(rule.targets);
this.noSelectedEndpoint = false;
this.realEndpointData.userName = rule.targets[0].username;
this.realEndpointData.password = FAKE_PASSWORD;
this.firstEndpointData = Object.assign({}, this.realEndpointData);
if (rule.filters) {
this.setFilter(rule.filters);
this.updateFilter(rule.filters);
@ -250,6 +272,9 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
if ($event && $event.target && event.target['value']) {
let selecedTarget: Target = this.targetList.find(target => target.id === +$event.target['value']);
this.setTarget([selecedTarget]);
this.noSelectedEndpoint = false;
this.realEndpointData.userName = selecedTarget.username;
this.firstEndpointData = Object.assign({}, this.realEndpointData);
}
}
@ -258,7 +283,12 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
}
selectedProject(project: Project): void {
this.setProject([project]);
if (!project) {
this.noSelectedProject = true;
}else {
this.noSelectedProject = false;
this.setProject([project]);
}
}
addNewFilter(): void {
@ -308,15 +338,15 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
selectTrigger($event: any): void {
if ($event && $event.target && $event.target['value']) {
let val: string = $event.target['value'];
if (val === this.triggerNames[1]) {
if (val === this.triggerNames[2]) {
this.isScheduleOpt = true;
this.isImmediate = false;
}
if (val === this.triggerNames[0]) {
if (val === this.triggerNames[1]) {
this.isScheduleOpt = false;
this.isImmediate = true;
}
if (val === this.triggerNames[2]) {
if (val === this.triggerNames[0]) {
this.isScheduleOpt = false;
this.isImmediate = false;
}
@ -381,7 +411,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
trigger['schedule_param']['weekday'] = 1;
}
}else {
if (trigger['kind'] === this.triggerNames[2]) {
if (trigger['kind'] === this.triggerNames[0]) {
this.isImmediate = false;
}
trigger['schedule_param'] = { type: this.scheduleNames[0],
@ -412,50 +442,86 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
onSubmit() {
// add new Replication rule
this.inProgress = true;
let endpointId: string | number = this.ruleForm.value.targets[0].id;
let pullData: { [key: string]: string | number } = this.initEndpointData();
if (compareValue(this.firstEndpointData, this.realEndpointData)) {
this.saveRuleOpe();
}else {
if (this.realEndpointData.userName !== this.firstEndpointData.userName) {
pullData.userName = this.realEndpointData.userName;
}else {
delete pullData.userName;
}
if (this.realEndpointData.password !== this.firstEndpointData.password) {
pullData.password = this.realEndpointData.password;
}else {
delete pullData.password;
}
pullData.id = endpointId;
this.repService.pingEndpoint(pullData)
.then((res: any) => {
delete pullData.id;
this.repService.updateEndpoint(endpointId, pullData)
.then((res: any) => {
this.saveRuleOpe();
})
.catch((error: any) => {
this.inProgress = false;
this.msgHandler.handleError(error);
});
})
.catch((error: any) => {
this.inProgress = false;
this.msgHandler.handleError('DESTINATION.TEST_CONNECTION_FAILURE');
return false;
});
}
}
saveRuleOpe(): void {
// add new Replication rule
let copyRuleForm: ReplicationRule = this.ruleForm.value;
copyRuleForm.trigger = this.setTriggerVaule(copyRuleForm.trigger);
if (!this.policyId) {
this.repService.createReplicationRule(copyRuleForm)
.then(() => {
this.msgHandler.showSuccess('REPLICATION.CREATED_SUCCESS');
this.inProgress = false;
this.isSubmitOver = true;
setTimeout(() => {
this.copyUpdateForm = Object.assign({}, this.ruleForm.value);
if (this.projectId) {
this.router.navigate(['harbor/projects', this.projectId, 'replications']);
}else {
this.router.navigate(['/harbor/replications']);
}
}, 2000);
this.msgHandler.showSuccess('REPLICATION.CREATED_SUCCESS');
this.inProgress = false;
this.isSubmitOver = true;
setTimeout(() => {
this.copyUpdateForm = Object.assign({}, this.ruleForm.value);
if (this.projectId) {
this.router.navigate(['harbor/projects', this.projectId, 'replications']);
}else {
this.router.navigate(['/harbor/replications']);
}
}, 2000);
}).catch((error: any) => {
}).catch((error: any) => {
this.inProgress = false;
this.msgHandler.handleError(error);
});
} else {
this.repService.updateReplicationRule(this.policyId, this.ruleForm.value)
.then(() => {
this.msgHandler.showSuccess('REPLICATION.UPDATED_SUCCESS');
this.inProgress = false;
this.isSubmitOver = true;
setTimeout(() => {
this.copyUpdateForm = Object.assign({}, this.ruleForm.value);
if (this.projectId) {
this.router.navigate(['harbor/projects', this.projectId, 'replications']);
}else {
this.router.navigate(['/harbor/replications']);
}
}, 2000);
this.msgHandler.showSuccess('REPLICATION.UPDATED_SUCCESS');
this.inProgress = false;
this.isSubmitOver = true;
setTimeout(() => {
this.copyUpdateForm = Object.assign({}, this.ruleForm.value);
if (this.projectId) {
this.router.navigate(['harbor/projects', this.projectId, 'replications']);
}else {
this.router.navigate(['/harbor/replications']);
}
}, 2000);
}).catch((error: any) => {
}).catch((error: any) => {
this.inProgress = false;
this.msgHandler.handleError(error);
});
}
}
openModal() {
@ -467,8 +533,10 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
Promise.all([this.repService.getEndpoints()]).then(res => {
this.targetList = res[0];
this.setTarget([this.targetList[this.targetList.length - 1]]);
this.noSelectedEndpoint = false;
this.realEndpointData.userName = this.targetList[this.targetList.length - 1].username;
this.firstEndpointData = Object.assign({}, this.realEndpointData);
});
this.noEndpointInfo = false;
}
}

View File

@ -23,9 +23,11 @@ label:first-child {
font-size: 15px;
left: -10px !important;
}
.endpointSelect{ width: 290px;}
.filterSelect{width: 320px;}
.filterSelect label{width: 160px;}
.inputWidth{width: 310px;}
.endpointSelect{ width: 290px; margin-right: 34px;}
.filterSelect{width: 350px;}
.filterSelect clr-icon{margin-left: 10px;}
.filterSelect label{width: 175px;}
.filterSelect label input{width: 100%;}
.cursor{cursor: pointer;}
.pull-left{float: left;}
@ -34,7 +36,9 @@ label:first-child {
.form-group{ min-height: 36px;}
.projectInput{float: left;}
.projectInput input{width: 185px;background-color: white;}
.switchIcon{width:20px;height:20px; margin-top: 2px;margin-left: 5px;}
.addEndpoint{ display: inline-block; line-height: 20px; margin-top: 8px;
vertical-align: bottom; padding-left:10px; cursor: pointer;}
.projectInput input{background-color: white;}
.switchIcon{width:20px;height:20px; margin-top: 16px;margin-left: 10px;}
.addEndpoint{ margin-top: .25em !important;}
.shadow{position: absolute;top: 8px;}
.shadow1{width:270px; height: 24px;background-color: #fafafa; z-index: 10; top:5px;}
.hoverBg:hover{display: none;}

View File

@ -2,37 +2,37 @@
<a class="cursor" *ngIf="!projectId" (click)="backReplication()">< {{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate}}</a>
<a class="cursor" *ngIf="projectId" (click)="backProjectReplication()"><{{'SIDE_NAV.PROJECTS' | translate}} &nbsp; {{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate | lowercase}}</a>
<h1 class="sub-header-title">{{headerTitle | translate}}</h1>
<form [formGroup]="ruleForm" (ngSubmit)="onSubmit()" novalidate>
<form [formGroup]="ruleForm" novalidate>
<section class="form-block">
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'REPLICATION.NAME' | translate}}<span class="colorRed">*</span></label>
<label class="col-md-8" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left"
[class.invalid]='(ruleForm.controls.name.touched && ruleForm.controls.name.invalid) || isRuleNameExist'>
<input type="text" id="ruleName" required formControlName="name" #ruleName (keyup)='checkRuleName()' autocomplete="off">
<input type="text" id="ruleName" class="inputWidth" required maxlength="255" formControlName="name" #ruleName (keyup)='checkRuleName()' autocomplete="off">
<span class="tooltip-content">{{ruleNameTooltip | translate}}</span>
</label><span class="spinner spinner-inline spinner-pos" [hidden]="!inNameChecking"></span>
</div>
<!--Description-->
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'REPLICATION.DESCRIPTION' | translate}}</label>
<textarea type="text" id="ruleDescription" style=" width: 355px;" row= 3; formControlName="description"></textarea>
<textarea type="text" id="ruleDescription" class="inputWidth" row= 3; formControlName="description"></textarea>
</div>
<!--Projects-->
<h4>{{'REPLICATION.SOURCE' | translate}}</h4>
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'PROJECT.PROJECTS' | translate}}<span class="colorRed">*</span></label>
<div formArrayName="projects">
<label class="col-md-4 form-group-label-override">{{'REPLICATION.SOURCE' | translate}}&nbsp;{{'PROJECT.PROJECTS' | translate | lowercase}}<span class="colorRed">*</span></label>
<div formArrayName="projects" [style.visibility]="noSelectedProject?'hidden':'visible'">
<div class="projectInput" *ngFor="let project of projects.controls; let i= index" [formGroupName]="i">
<input formControlName="name" class="label" readonly value="name">
<input formControlName="name" type="text" class="inputWidth" disabled value="name">
</div>
</div>
<clr-icon *ngIf="!(noProjectInfo || projectId)" shape="search" class="is-solid switchIcon" (click)="openProjectModel()"></clr-icon>
<label *ngIf="noProjectInfo" class="colorRed">{{noProjectInfo | translate}}</label>
<clr-icon *ngIf="!(noProjectInfo.length !=0 || projectId)" shape="search" class="is-solid switchIcon" (click)="openProjectModel()"></clr-icon>
<label *ngIf="noProjectInfo.length != 0" class="colorRed">{{noProjectInfo | translate}}</label>
<div class="shadow" [hidden]="!noSelectedProject || noProjectInfo.length != 0"><input type="text" class="inputWidth" disabled ></div>
</div>
<!--images/Filter-->
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'REPLICATION.FILTER' | translate}}</label>
<label class="col-md-4 form-group-label-override">{{'REPLICATION.SOURCE_IMAGES_FILTER' | translate}}</label>
<div formArrayName="filters">
<div class="filterSelect" *ngFor="let filter of filters.controls; let i=index" [formGroupName]="i">
<div>
@ -53,43 +53,44 @@
<clr-icon shape="plus-circle" class="is-solid" [hidden]="isFilterHide" (click)="addNewFilter()" style="margin-top: 11px;"></clr-icon>
</div>
<!--Targets-->
<h4>{{'REPLICATION.TARGETS' | translate}}</h4>
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'DESTINATION.ENDPOINT' | translate}} <span class="colorRed">*</span></label>
<div formArrayName="targets">
<div class="select endpointSelect pull-left" *ngFor="let target of targets.controls; let i= index" [formGroupName]="i">
<select id="ruleTarget" (change)="targetChange($event)" formControlName="id">
<select id="ruleTarget " class="inputWidth" (mouseenter)="noSelectedEndpoint= false" (change)="targetChange($event)" formControlName="id">
<option *ngFor="let target of targetList" value="{{target.id}}">{{target.name}}: {{target.endpoint}}</option>
</select>
</div>
<a class="addEndpoint" (click)="openModal()"><clr-icon shape="plus" style="vertical-align: sub;"></clr-icon>{{'REPLICATION.NEW' | translate}}</a>
</div>
<button class="btn btn-info btn-sm addEndpoint" (click)="openModal()"><clr-icon shape="plus"></clr-icon>&nbsp;{{'REPLICATION.NEW' | translate}}</button>
<div [hidden]="noSelectedEndpoint">userName: &nbsp;&nbsp;<input type="text" [(ngModel)]="realEndpointData.userName" [ngModelOptions]="{standalone:true}"></div>
<div [hidden]="noSelectedEndpoint">password: &nbsp;&nbsp;<input type="password" [(ngModel)]="realEndpointData.password" [ngModelOptions]="{standalone:true}"></div>
</div>
<div class="shadow shadow1 hoverBg" #shadowDiv [hidden]="!noSelectedEndpoint || !targetList.length"></div>
</div>
<!--Trigger-->
<h4>{{'REPLICATION.TRIGGER' | translate}}</h4>
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'REPLICATION.MODE' | translate}}</label>
<label class="col-md-4 form-group-label-override">{{'REPLICATION.TRIGGER_MODE' | translate}}</label>
<div formGroupName="trigger">
<!--on trigger-->
<div class="select floatSet pull-left">
<div class="select floatSet">
<select id="ruleTrigger" formControlName="kind" (change)="selectTrigger($event)">
<option value="Manual">{{'REPLICATION.MANUAL' | translate}}</option>
<option value="Immediate">{{'REPLICATION.IMMEDIATE' | translate}}</option>
<option value="Scheduled">{{'REPLICATION.SCHEDULE' | translate}}</option>
<option value="Manual">{{'REPLICATION.MANUAL' | translate}}</option>
</select>
</div>
<!--on push-->
<div style="float: left;" formGroupName="schedule_param">
<div class="select floatSet pull-left" [hidden]="!isScheduleOpt">
<div formGroupName="schedule_param">
<div class="select floatSet" [hidden]="!isScheduleOpt">
<select name="scheduleType" formControlName="type" (change)="selectSchedule($event)">
<option value="Daily">{{'REPLICATION.DAILY' | translate}}</option>
<option value="Weekly">{{'REPLICATION.WEEKLY' | translate}}</option>
</select>
</div>
<!--weekly-->
<span style="float: left;" [hidden]="!weeklySchedule || !isScheduleOpt">on &nbsp;&nbsp;</span>
<div [hidden]="!weeklySchedule || !isScheduleOpt" class="select floatSet pull-left">
<span [hidden]="!weeklySchedule || !isScheduleOpt">on &nbsp;&nbsp;</span>
<div [hidden]="!weeklySchedule || !isScheduleOpt" class="select floatSet">
<select name="scheduleDay" formControlName="weekday">
<option value="1">{{'WEEKLY.MONDAY' | translate}}</option>
<option value="2">{{'WEEKLY.TUESDAY' | translate}}</option>
@ -110,22 +111,18 @@
{{'REPLICATION.DELETE_REMOTE_IMAGES' | translate}}
</clr-checkbox>
</div>
</div>
<!--Setting-->
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'REPLICATION.SETTING' | translate}}</label>
<div class="col-lg-7 padLeft0">
<clr-checkbox [clrChecked]="true" id="ruleExit" formControlName="replicate_existing_image_now">
{{'REPLICATION.REPLICATE_IMMEDIATE' | translate}}
</clr-checkbox>
</div>
<div style="width: 100%;" >
<clr-checkbox [clrChecked]="true" id="ruleExit" formControlName="replicate_existing_image_now">
{{'REPLICATION.REPLICATE_IMMEDIATE' | translate}}
</clr-checkbox>
</div>
</div>
<div class="offset-md-4">
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
<br>
<button type="button" id="ruleBtnCancel" class="btn btn-outline" [disabled]="!hasFormChange()" (click)="onCancel()">{{ 'BUTTON.CANCEL' | translate }}</button>
<button type="submit" id="ruleBtnOk" class="btn btn-primary" [disabled]="!ruleForm.valid || !isVaild || !hasFormChange()">{{ 'BUTTON.OK' | translate }}</button>
<button type="button" id="ruleBtnCancel" class="btn btn-outline" [disabled]="!hasFormChange() || this.inProgress || this.isSubmitOver" (click)="onCancel()">{{ 'BUTTON.CANCEL' | translate }}</button>
<button type="submit" id="ruleBtnOk" class="btn btn-primary" (click)="onSubmit()" [disabled]="!ruleForm.valid || !isVaild || !hasFormChange()">{{ 'BUTTON.OK' | translate }}</button>
</div><!-- [disabled]="!ruleForm.valid"-->
</section>
</form>

View File

@ -72,4 +72,31 @@ export class ReplicationRuleServie {
.catch(error => Promise.reject(error));
}
public updateEndpoint(endpointId: number | string, endpoint: any): Promise<any> | any {
if (!endpointId || endpointId <= 0) {
return Promise.reject('Bad request argument.');
}
if (!endpoint) {
return Promise.reject('Invalid endpoint.');
}
let requestUrl: string = `/api/targets/${endpointId}`;
return this.http
.put(requestUrl, JSON.stringify(endpoint), HTTP_JSON_OPTIONS)
.toPromise()
.then(response=>response.status)
.catch(error=>Promise.reject(error));
}
public pingEndpoint(endpoint: any): Promise<any> | any {
if (!endpoint) {
return Promise.reject('Invalid endpoint.');
}
let requestUrl: string = `/api/targets/ping`;
return this.http
.post(requestUrl, endpoint, HTTP_JSON_OPTIONS)
.toPromise()
.then(response=>response.status)
.catch(error=>Promise.reject(error));
}
}

View File

@ -4,15 +4,26 @@ import {Project} from "../../project/project";
*/
export class Target {
id: 0;
endpoint: 'string';
name: 'string';
username: 'string';
password: 'string';
type: 0;
id: number;
endpoint: string;
name: string;
username: string;
password: string;
type: number;
insecure: true;
creation_time: 'string';
update_time: 'string';
creation_time: string;
update_time: string;
constructor() {
this.id = -1;
this.endpoint = "";
this.name = "";
this.username = "";
this.password = "";
this.type = 0;
this.insecure = true;
this.creation_time = "";
this.update_time = "";
}
}
export class Filter {

View File

@ -277,6 +277,7 @@ export class UserComponent implements OnInit, OnDestroy {
//Refresh the user list
refreshUser(from: number, to: number): void {
this.selectedRow = [];
//Start to get
this.currentTerm = '';
this.onGoing = true;

View File

@ -324,7 +324,7 @@
"JOB_LOG_VIEWER": "View Replication Job Log",
"NO_ENDPOINT_INFO": "Please go to registries and add an endpoint first",
"NO_PROJECT_INFO": "Please go to projects and add a project name first",
"FILTER": "Filter",
"SOURCE_IMAGES_FILTER": "Source images filter",
"SCHEDULE": "Scheduled",
"MANUAL": "Manual",
"IMMEDIATE": "Immediate",

View File

@ -324,7 +324,7 @@
"JOB_LOG_VIEWER": "View Replication Job Log",
"NO_ENDPOINT_INFO": "Please go to registries and add an endpoint first",
"NO_PROJECT_INFO": "Please go to projects and add a project name first",
"FILTER": "Filter",
"SOURCE_IMAGES_FILTER": "Source images filter",
"SCHEDULE": "Scheduled",
"MANUAL": "Manual",
"IMMEDIATE": "Immediate",

View File

@ -324,7 +324,7 @@
"JOB_LOG_VIEWER": "查看复制任务日志",
"NO_ENDPOINT_INFO": "请先添加目标",
"NO_PROJECT_INFO": "请先去项目添加一个新的项目名称",
"FILTER": "过滤",
"SOURCE_IMAGES_FILTER": "源镜像过滤",
"SCHEDULE": "定时",
"MANUAL": "手动",
"IMMEDIATE": "即刻",
@ -335,7 +335,7 @@
"TARGETS":"目标",
"MODE": "模式",
"TRIGGER_MODE": "触发模式",
"SOURCE": "源",
"SOURCE": "源",
"REPLICATE": "复制",
"DELETE_REMOTE_IMAGES":"删除本地镜像时同时也删除远程的镜像。",
"REPLICATE_IMMEDIATE":"立即复制现有的镜像。",