mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-04 16:13:35 +01:00
Merge pull request #7216 from zhoumeina/replication_ng
Create replication rule -- remove project logic and add dynamic trigger logic.
This commit is contained in:
commit
690f868d15
@ -34,13 +34,16 @@ describe("CreateEditEndpointComponent (inline template)", () => {
|
|||||||
url: "https://10.117.4.151"
|
url: "https://10.117.4.151"
|
||||||
};
|
};
|
||||||
|
|
||||||
let mockAdapter: [Adapter] = [{
|
let mockAdapters: Adapter[] = [{
|
||||||
type: "Harbor",
|
type: "Harbor",
|
||||||
description: "test",
|
description: "test",
|
||||||
supported_resource_types: [
|
supported_resource_filters: [
|
||||||
"repository"
|
{
|
||||||
|
"type": "Name",
|
||||||
|
"style": "input"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
supported_resource_filters: null
|
supported_triggers: []
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let comp: CreateEditEndpointComponent;
|
let comp: CreateEditEndpointComponent;
|
||||||
@ -77,7 +80,7 @@ describe("CreateEditEndpointComponent (inline template)", () => {
|
|||||||
|
|
||||||
endpointService = fixture.debugElement.injector.get(EndpointService);
|
endpointService = fixture.debugElement.injector.get(EndpointService);
|
||||||
spyAdapter = spyOn(endpointService, "getAdapters").and.returnValue(
|
spyAdapter = spyOn(endpointService, "getAdapters").and.returnValue(
|
||||||
of(mockAdapter)
|
of(mockAdapters)
|
||||||
);
|
);
|
||||||
|
|
||||||
spy = spyOn(endpointService, "getEndpoint").and.returnValue(
|
spy = spyOn(endpointService, "getEndpoint").and.returnValue(
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<div class="form-group form-group-override">
|
<div class="form-group form-group-override">
|
||||||
<label class="form-group-label-override">{{'REPLICATION.REPLI_MODE' | translate}}</label>
|
<label class="form-group-label-override">{{'REPLICATION.REPLI_MODE' | translate}}</label>
|
||||||
<div class="radio" style="display:inherit;">
|
<div class="radio" style="display:inherit;">
|
||||||
<input type="radio" id="push_base" name="replicationMode" [value]=true [(ngModel)]="isPushMode" [ngModelOptions]="{standalone: true}">
|
<input type="radio" id="push_base" name="replicationMode" [value]=true [(ngModel)]="isPushMode" (change)="modeChange()" [ngModelOptions]="{standalone: true}">
|
||||||
<label for="push_base">Push-based</label>
|
<label for="push_base">Push-based</label>
|
||||||
<input type="radio" id="pull_base" name="replicationMode" [value]=false [(ngModel)]="isPushMode" [ngModelOptions]="{standalone: true}">
|
<input type="radio" id="pull_base" name="replicationMode" [value]=false [(ngModel)]="isPushMode" [ngModelOptions]="{standalone: true}">
|
||||||
<label for="pull_base">Pull-based</label>
|
<label for="pull_base">Pull-based</label>
|
||||||
@ -127,14 +127,12 @@
|
|||||||
<!--on trigger-->
|
<!--on trigger-->
|
||||||
<div class="select floatSetPar">
|
<div class="select floatSetPar">
|
||||||
<select id="ruleTrigger" formControlName="kind" (change)="selectTrigger($event)">
|
<select id="ruleTrigger" formControlName="kind" (change)="selectTrigger($event)">
|
||||||
<option value="Manual">{{'REPLICATION.MANUAL' | translate}}</option>
|
<option *ngFor="let trigger of supportedTriggers" [value]="trigger">{{trigger }}</option>
|
||||||
<option value="Immediate">{{'REPLICATION.IMMEDIATE' | translate}}</option>
|
|
||||||
<option value="Scheduled">{{'REPLICATION.SCHEDULE' | translate}}</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<!--on push-->
|
<!--on push-->
|
||||||
<div formGroupName="schedule_param">
|
<div formGroupName="schedule_param">
|
||||||
<div [hidden]="!isScheduleOpt">
|
<div [hidden]="isNotSchedule()">
|
||||||
<label>Cron String</label>
|
<label>Cron String</label>
|
||||||
<label for="targetCron" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right">
|
<label for="targetCron" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right">
|
||||||
<input type="text" name=targetCron id="targetCron" required class="form-control cron-input" formControlName="cron">
|
<input type="text" name=targetCron id="targetCron" required class="form-control cron-input" formControlName="cron">
|
||||||
@ -145,7 +143,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div [hidden]="!isImmediate" class="clr-form-control rule-width">
|
<div [hidden]="isNotEventBased()" class="clr-form-control rule-width">
|
||||||
<clr-checkbox-wrapper>
|
<clr-checkbox-wrapper>
|
||||||
<input type="checkbox" clrCheckbox [checked]="false" id="ruleDeletion" formControlName="deletion" class="clr-checkbox">
|
<input type="checkbox" clrCheckbox [checked]="false" id="ruleDeletion" formControlName="deletion" class="clr-checkbox">
|
||||||
<label for="ruleDeletion" class="clr-control-label">{{'REPLICATION.DELETE_REMOTE_IMAGES' | translate}}</label>
|
<label for="ruleDeletion" class="clr-control-label">{{'REPLICATION.DELETE_REMOTE_IMAGES' | translate}}</label>
|
||||||
|
@ -17,7 +17,8 @@ import {
|
|||||||
ReplicationRule,
|
ReplicationRule,
|
||||||
ReplicationJob,
|
ReplicationJob,
|
||||||
Endpoint,
|
Endpoint,
|
||||||
ReplicationJobItem
|
ReplicationJobItem,
|
||||||
|
Adapter
|
||||||
} from "../service/interface";
|
} from "../service/interface";
|
||||||
|
|
||||||
import { ErrorHandler } from "../error-handler/error-handler";
|
import { ErrorHandler } from "../error-handler/error-handler";
|
||||||
@ -160,6 +161,38 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
|||||||
deletion: false
|
deletion: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mockAdapter: Adapter = {
|
||||||
|
"type": "harbor",
|
||||||
|
"description": "",
|
||||||
|
"supported_resource_filters": [
|
||||||
|
{
|
||||||
|
"type": "Name",
|
||||||
|
"style": "input"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Version",
|
||||||
|
"style": "input"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"style": "input"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Resource",
|
||||||
|
"style": "radio",
|
||||||
|
"values": [
|
||||||
|
"repository",
|
||||||
|
"chart"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"supported_triggers": [
|
||||||
|
"Manual",
|
||||||
|
"Scheduled",
|
||||||
|
"EventBased"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
let fixture: ComponentFixture<ReplicationComponent>;
|
let fixture: ComponentFixture<ReplicationComponent>;
|
||||||
let fixtureCreate: ComponentFixture<CreateEditRuleComponent>;
|
let fixtureCreate: ComponentFixture<CreateEditRuleComponent>;
|
||||||
|
|
||||||
@ -173,10 +206,11 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
|||||||
let spyOneRule: jasmine.Spy;
|
let spyOneRule: jasmine.Spy;
|
||||||
|
|
||||||
let spyJobs: jasmine.Spy;
|
let spyJobs: jasmine.Spy;
|
||||||
|
let spyAdapter: jasmine.Spy;
|
||||||
let spyEndpoint: jasmine.Spy;
|
let spyEndpoint: jasmine.Spy;
|
||||||
|
|
||||||
let config: IServiceConfig = {
|
let config: IServiceConfig = {
|
||||||
replicationBaseEndpoint: "/api/replication/executions/testing",
|
replicationBaseEndpoint: "/api/replication/testing",
|
||||||
targetBaseEndpoint: "/api/registries/testing"
|
targetBaseEndpoint: "/api/registries/testing"
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -230,6 +264,8 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
|||||||
spyJobs = spyOn(replicationService, "getExecutions").and.returnValues(
|
spyJobs = spyOn(replicationService, "getExecutions").and.returnValues(
|
||||||
of(mockJob));
|
of(mockJob));
|
||||||
|
|
||||||
|
spyAdapter = spyOn(replicationService, "getReplicationAdapter").and.returnValues(
|
||||||
|
of(mockAdapter));
|
||||||
spyEndpoint = spyOn(endpointService, "getEndpoints").and.returnValues(
|
spyEndpoint = spyOn(endpointService, "getEndpoints").and.returnValues(
|
||||||
of(mockEndpoints)
|
of(mockEndpoints)
|
||||||
);
|
);
|
||||||
@ -239,6 +275,7 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
|||||||
|
|
||||||
it("Should open creation modal and load endpoints", async(() => {
|
it("Should open creation modal and load endpoints", async(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
compCreate.initAdapter("harbor");
|
||||||
compCreate.openCreateEditRule();
|
compCreate.openCreateEditRule();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@ -254,6 +291,7 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
|||||||
|
|
||||||
it("Should open modal to edit replication rule", async(() => {
|
it("Should open modal to edit replication rule", async(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
compCreate.initAdapter("harbor");
|
||||||
compCreate.openCreateEditRule(mockRule.id);
|
compCreate.openCreateEditRule(mockRule.id);
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
EventEmitter,
|
EventEmitter,
|
||||||
Output
|
Output
|
||||||
} from "@angular/core";
|
} from "@angular/core";
|
||||||
import { Filter, ReplicationRule, Endpoint, Label } from "../service/interface";
|
import { Filter, ReplicationRule, Endpoint, Label, Adapter } from "../service/interface";
|
||||||
import { Subject, Subscription } from "rxjs";
|
import { Subject, Subscription } from "rxjs";
|
||||||
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
|
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
|
||||||
import { FormArray, FormBuilder, FormGroup, Validators, FormControl } from "@angular/forms";
|
import { FormArray, FormBuilder, FormGroup, Validators, FormControl } from "@angular/forms";
|
||||||
@ -51,8 +51,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
selectedProjectList: Project[] = [];
|
selectedProjectList: Project[] = [];
|
||||||
isFilterHide = false;
|
isFilterHide = false;
|
||||||
weeklySchedule: boolean;
|
weeklySchedule: boolean;
|
||||||
isScheduleOpt: boolean;
|
|
||||||
isImmediate = false;
|
|
||||||
noProjectInfo = "";
|
noProjectInfo = "";
|
||||||
noEndpointInfo = "";
|
noEndpointInfo = "";
|
||||||
isPushMode = true;
|
isPushMode = true;
|
||||||
@ -60,7 +58,11 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
noSelectedEndpoint = true;
|
noSelectedEndpoint = true;
|
||||||
filterCount = 0;
|
filterCount = 0;
|
||||||
alertClosed = false;
|
alertClosed = false;
|
||||||
triggerNames: string[] = ["Manual", "Immediate", "Scheduled"];
|
TRIGGER_TYPES = {
|
||||||
|
MANUAL: "Manual",
|
||||||
|
SCHEDULED: "Scheduled",
|
||||||
|
EVENT_BASED: "EventBased"
|
||||||
|
};
|
||||||
filterSelect: string[] = ["type", "repository", "tag", "label"];
|
filterSelect: string[] = ["type", "repository", "tag", "label"];
|
||||||
ruleNameTooltip = "REPLICATION.NAME_TOOLTIP";
|
ruleNameTooltip = "REPLICATION.NAME_TOOLTIP";
|
||||||
headerTitle = "REPLICATION.ADD_POLICY";
|
headerTitle = "REPLICATION.ADD_POLICY";
|
||||||
@ -71,24 +73,19 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
inNameChecking = false;
|
inNameChecking = false;
|
||||||
isRuleNameValid = true;
|
isRuleNameValid = true;
|
||||||
nameChecker: Subject<string> = new Subject<string>();
|
nameChecker: Subject<string> = new Subject<string>();
|
||||||
proNameChecker: Subject<string> = new Subject<string>();
|
|
||||||
firstClick = 0;
|
firstClick = 0;
|
||||||
policyId: number;
|
policyId: number;
|
||||||
labelInputVal = '';
|
labelInputVal = '';
|
||||||
filterLabelInfo: Label[] = []; // store filter selected labels` id
|
filterLabelInfo: Label[] = []; // store filter selected labels` id
|
||||||
deletedLabelCount = 0;
|
deletedLabelCount = 0;
|
||||||
deletedLabelInfo: string;
|
deletedLabelInfo: string;
|
||||||
|
|
||||||
namespaceList: [any] = [{
|
|
||||||
id: 1,
|
|
||||||
name: "namespace1"
|
|
||||||
}];
|
|
||||||
|
|
||||||
confirmSub: Subscription;
|
confirmSub: Subscription;
|
||||||
ruleForm: FormGroup;
|
ruleForm: FormGroup;
|
||||||
formArrayLabel: FormArray;
|
formArrayLabel: FormArray;
|
||||||
copyUpdateForm: ReplicationRule;
|
copyUpdateForm: ReplicationRule;
|
||||||
cronString: string;
|
cronString: string;
|
||||||
|
supportedTriggers: string[];
|
||||||
|
supportedFilters: Filter[];
|
||||||
|
|
||||||
@Input() projectId: number;
|
@Input() projectId: number;
|
||||||
@Input() projectName: string;
|
@Input() projectName: string;
|
||||||
@ -98,24 +95,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
@Output() reload = new EventEmitter<boolean>();
|
@Output() reload = new EventEmitter<boolean>();
|
||||||
|
|
||||||
@ViewChild(InlineAlertComponent) inlineAlert: InlineAlertComponent;
|
@ViewChild(InlineAlertComponent) inlineAlert: InlineAlertComponent;
|
||||||
|
|
||||||
emptyProject = {
|
|
||||||
project_id: -1,
|
|
||||||
name: ""
|
|
||||||
};
|
|
||||||
emptyEndpoint = {
|
|
||||||
id: -1,
|
|
||||||
credential: {
|
|
||||||
access_key: "",
|
|
||||||
access_secret: "",
|
|
||||||
type: ""
|
|
||||||
},
|
|
||||||
description: "",
|
|
||||||
insecure: false,
|
|
||||||
name: "",
|
|
||||||
type: "",
|
|
||||||
url: "",
|
|
||||||
};
|
|
||||||
constructor(
|
constructor(
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private repService: ReplicationService,
|
private repService: ReplicationService,
|
||||||
@ -138,20 +117,21 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initAdapter(type: string): void {
|
||||||
|
this.repService.getReplicationAdapter(type).subscribe(adapter => {
|
||||||
|
this.supportedFilters = adapter.supported_resource_filters;
|
||||||
|
this.supportedTriggers = adapter.supported_triggers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (this.withAdmiral) {
|
|
||||||
this.filterSelect = ["type", "repository", "tag"];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.endpointService.getEndpoints().subscribe(endPoints => {
|
this.endpointService.getEndpoints().subscribe(endPoints => {
|
||||||
this.targetList = endPoints || [];
|
this.targetList = endPoints || [];
|
||||||
this.sourceList = endPoints || [];
|
this.sourceList = endPoints || [];
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
|
this.initAdapter("harbor");
|
||||||
|
|
||||||
this.nameChecker
|
this.nameChecker
|
||||||
.pipe(debounceTime(300))
|
.pipe(debounceTime(300))
|
||||||
.pipe(distinctUntilChanged())
|
.pipe(distinctUntilChanged())
|
||||||
@ -178,50 +158,22 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modeChange(): void {
|
||||||
|
if (this.isPushMode) {
|
||||||
|
this.initAdapter("harbor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sourceChange($event): void {
|
sourceChange($event): void {
|
||||||
if ($event && $event.target) {
|
this.noSelectedEndpoint = false;
|
||||||
if ($event.target["value"] === "-1") {
|
let selectId = this.ruleForm.get('src_registry_id').value;
|
||||||
this.noSelectedEndpoint = true;
|
let selecedTarget: Endpoint = this.sourceList.find(
|
||||||
return;
|
source => source.id === selectId
|
||||||
}
|
);
|
||||||
let selecedTarget: Endpoint = this.sourceList.find(
|
|
||||||
source => source.id === +$event.target["value"]
|
this.initAdapter(selecedTarget.type);
|
||||||
);
|
|
||||||
this.noSelectedEndpoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.proNameChecker
|
|
||||||
.pipe(debounceTime(500))
|
|
||||||
.pipe(distinctUntilChanged())
|
|
||||||
.subscribe((resp: string) => {
|
|
||||||
let name = this.ruleForm.controls["projects"].value[0].name;
|
|
||||||
this.noProjectInfo = "";
|
|
||||||
this.selectedProjectList = [];
|
|
||||||
this.proService.listProjects(name, undefined)
|
|
||||||
.subscribe((res: any) => {
|
|
||||||
if (res) {
|
|
||||||
this.selectedProjectList = res.slice(0, 10);
|
|
||||||
// if input value exit in project list
|
|
||||||
let pro = res.find((data: any) => data.name === name);
|
|
||||||
if (!pro) {
|
|
||||||
this.noProjectInfo = "REPLICATION.NO_PROJECT_INFO";
|
|
||||||
this.noSelectedProject = true;
|
|
||||||
} else {
|
|
||||||
this.noProjectInfo = "";
|
|
||||||
this.noSelectedProject = false;
|
|
||||||
this.setProject([pro]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.noProjectInfo = "REPLICATION.NO_PROJECT_INFO";
|
|
||||||
this.noSelectedProject = true;
|
|
||||||
}
|
|
||||||
}, (error: any) => {
|
|
||||||
this.errorHandler.error(error);
|
|
||||||
this.noProjectInfo = "REPLICATION.NO_PROJECT_INFO";
|
|
||||||
this.noSelectedProject = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
@ -231,9 +183,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
if (this.nameChecker) {
|
if (this.nameChecker) {
|
||||||
this.nameChecker.unsubscribe();
|
this.nameChecker.unsubscribe();
|
||||||
}
|
}
|
||||||
if (this.proNameChecker) {
|
|
||||||
this.proNameChecker.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
get src_namespaces(): FormArray { return this.ruleForm.get('src_namespaces') as FormArray; }
|
get src_namespaces(): FormArray { return this.ruleForm.get('src_namespaces') as FormArray; }
|
||||||
|
|
||||||
@ -255,7 +204,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
dest_registry_id: new FormControl(),
|
dest_registry_id: new FormControl(),
|
||||||
dest_namespace: "",
|
dest_namespace: "",
|
||||||
trigger: this.fb.group({
|
trigger: this.fb.group({
|
||||||
kind: this.triggerNames[0],
|
kind: '',
|
||||||
schedule_param: this.fb.group({
|
schedule_param: this.fb.group({
|
||||||
cron: ""
|
cron: ""
|
||||||
})
|
})
|
||||||
@ -265,12 +214,24 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectTrigger($event: any): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isNotSchedule(): boolean {
|
||||||
|
return this.ruleForm.get("trigger").get("kind").value !== this.TRIGGER_TYPES.SCHEDULED;
|
||||||
|
}
|
||||||
|
|
||||||
|
isNotEventBased(): boolean {
|
||||||
|
return this.ruleForm.get("trigger").get("kind").value !== this.TRIGGER_TYPES.EVENT_BASED;
|
||||||
|
}
|
||||||
|
|
||||||
initForm(): void {
|
initForm(): void {
|
||||||
this.ruleForm.reset({
|
this.ruleForm.reset({
|
||||||
name: "",
|
name: "",
|
||||||
description: "",
|
description: "",
|
||||||
trigger: {
|
trigger: {
|
||||||
kind: this.triggerNames[0],
|
kind: this.supportedTriggers[0],
|
||||||
schedule_param: {
|
schedule_param: {
|
||||||
cron: ""
|
cron: ""
|
||||||
}
|
}
|
||||||
@ -278,7 +239,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
deletion: false
|
deletion: false
|
||||||
});
|
});
|
||||||
this.setFilter([]);
|
this.setFilter([]);
|
||||||
|
|
||||||
this.copyUpdateForm = clone(this.ruleForm.value);
|
this.copyUpdateForm = clone(this.ruleForm.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,15 +305,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get projects(): FormArray {
|
|
||||||
return this.ruleForm.get("projects") as FormArray;
|
|
||||||
}
|
|
||||||
setProject(projects: Project[]) {
|
|
||||||
const projectFGs = projects.map(project => this.fb.group(project));
|
|
||||||
const projectFormArray = this.fb.array(projectFGs);
|
|
||||||
this.ruleForm.setControl("projects", projectFormArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
get filters(): FormArray {
|
get filters(): FormArray {
|
||||||
return this.ruleForm.get("filters") as FormArray;
|
return this.ruleForm.get("filters") as FormArray;
|
||||||
}
|
}
|
||||||
@ -363,8 +314,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
this.ruleForm.setControl("filters", filterFormArray);
|
this.ruleForm.setControl("filters", filterFormArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
initFilter(name: string) {
|
initFilter(name: string) {
|
||||||
return this.fb.group({
|
return this.fb.group({
|
||||||
kind: name,
|
kind: name,
|
||||||
@ -434,14 +383,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the form validation
|
|
||||||
handleValidation(): void {
|
|
||||||
let cont = this.ruleForm.controls["projects"];
|
|
||||||
if (cont && cont.valid) {
|
|
||||||
this.proNameChecker.next(cont.value[0].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
focusClear($event: any): void {
|
focusClear($event: any): void {
|
||||||
if (this.policyId < 0 && this.firstClick === 0) {
|
if (this.policyId < 0 && this.firstClick === 0) {
|
||||||
if ($event && $event.target && $event.target["value"]) {
|
if ($event && $event.target && $event.target["value"]) {
|
||||||
@ -455,25 +396,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
this.selectedProjectList = [];
|
this.selectedProjectList = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedProjectName(projectName: string) {
|
|
||||||
this.noSelectedProject = false;
|
|
||||||
let pro: Project = this.selectedProjectList.find(
|
|
||||||
data => data.name === projectName
|
|
||||||
);
|
|
||||||
this.setProject([pro]);
|
|
||||||
this.selectedProjectList = [];
|
|
||||||
this.noProjectInfo = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedProject(project: Project): void {
|
|
||||||
if (!project) {
|
|
||||||
this.noSelectedProject = true;
|
|
||||||
} else {
|
|
||||||
this.noSelectedProject = false;
|
|
||||||
this.setProject([project]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addNewNamespace(): void {
|
addNewNamespace(): void {
|
||||||
this.src_namespaces.push(new FormControl());
|
this.src_namespaces.push(new FormControl());
|
||||||
}
|
}
|
||||||
@ -541,26 +463,9 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectTrigger($event: any): void {
|
|
||||||
if ($event && $event.target && $event.target["value"]) {
|
|
||||||
let val: string = $event.target["value"];
|
|
||||||
if (val === this.triggerNames[2]) {
|
|
||||||
this.isScheduleOpt = true;
|
|
||||||
this.isImmediate = false;
|
|
||||||
}
|
|
||||||
if (val === this.triggerNames[1]) {
|
|
||||||
this.isScheduleOpt = false;
|
|
||||||
this.isImmediate = true;
|
|
||||||
}
|
|
||||||
if (val === this.triggerNames[0]) {
|
|
||||||
this.isScheduleOpt = false;
|
|
||||||
this.isImmediate = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replication Schedule select value exchange
|
// Replication Schedule select value exchange
|
||||||
selectSchedule($event: any): void {
|
selectSchedule($event: any): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkRuleName(): void {
|
checkRuleName(): void {
|
||||||
@ -634,7 +539,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
// add new Replication rule
|
// add new Replication rule
|
||||||
this.inProgress = true;
|
this.inProgress = true;
|
||||||
let copyRuleForm: ReplicationRule = this.ruleForm.value;
|
let copyRuleForm: ReplicationRule = this.ruleForm.value;
|
||||||
copyRuleForm.trigger = null;
|
|
||||||
if (this.isPushMode) {
|
if (this.isPushMode) {
|
||||||
copyRuleForm.src_registry_id = null;
|
copyRuleForm.src_registry_id = null;
|
||||||
} else {
|
} else {
|
||||||
@ -688,8 +592,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
this.deletedLabelCount = 0;
|
this.deletedLabelCount = 0;
|
||||||
|
|
||||||
this.weeklySchedule = false;
|
this.weeklySchedule = false;
|
||||||
this.isScheduleOpt = false;
|
|
||||||
this.isImmediate = false;
|
|
||||||
this.policyId = -1;
|
this.policyId = -1;
|
||||||
this.createEditRuleOpened = true;
|
this.createEditRuleOpened = true;
|
||||||
this.filterLabelInfo = [];
|
this.filterLabelInfo = [];
|
||||||
|
@ -93,13 +93,16 @@ describe("EndpointComponent (inline template)", () => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
let mockAdapter: [Adapter] = [{
|
let mockAdapters: Adapter[] = [{
|
||||||
type: "Harbor",
|
type: "Harbor",
|
||||||
description: "test",
|
description: "test",
|
||||||
supported_resource_types: [
|
supported_resource_filters: [
|
||||||
"repository"
|
{
|
||||||
|
"type": "Name",
|
||||||
|
"style": "input"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
supported_resource_filters: null
|
supported_triggers: []
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let comp: EndpointComponent;
|
let comp: EndpointComponent;
|
||||||
@ -143,7 +146,7 @@ describe("EndpointComponent (inline template)", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
spyAdapter = spyOn(endpointService, "getAdapters").and.returnValue(
|
spyAdapter = spyOn(endpointService, "getAdapters").and.returnValue(
|
||||||
of(mockAdapter)
|
of(mockAdapters)
|
||||||
);
|
);
|
||||||
|
|
||||||
spyOnRules = spyOn(
|
spyOnRules = spyOn(
|
||||||
|
@ -81,9 +81,8 @@ export const DefaultServiceConfig: IServiceConfig = {
|
|||||||
repositoryBaseEndpoint: "/api/repositories",
|
repositoryBaseEndpoint: "/api/repositories",
|
||||||
logBaseEndpoint: "/api/logs",
|
logBaseEndpoint: "/api/logs",
|
||||||
targetBaseEndpoint: "/api/registries",
|
targetBaseEndpoint: "/api/registries",
|
||||||
replicationBaseEndpoint: "/api/replication/executions",
|
replicationBaseEndpoint: "/api/replication",
|
||||||
replicationRuleEndpoint: "/api/replication/policies",
|
replicationRuleEndpoint: "/api/replication/policies",
|
||||||
adapterEndpoint: "api/replication/adapters",
|
|
||||||
vulnerabilityScanningBaseEndpoint: "/api/repositories",
|
vulnerabilityScanningBaseEndpoint: "/api/repositories",
|
||||||
projectPolicyEndpoint: "/api/projects/configs",
|
projectPolicyEndpoint: "/api/projects/configs",
|
||||||
projectBaseEndpoint: "/api/projects",
|
projectBaseEndpoint: "/api/projects",
|
||||||
|
@ -138,7 +138,7 @@ describe('Replication Component (inline template)', () => {
|
|||||||
|
|
||||||
let config: IServiceConfig = {
|
let config: IServiceConfig = {
|
||||||
replicationRuleEndpoint: '/api/policies/replication/testing',
|
replicationRuleEndpoint: '/api/policies/replication/testing',
|
||||||
replicationBaseEndpoint: '/api/replication/executions/testing'
|
replicationBaseEndpoint: '/api/replication/testing'
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
|
@ -54,11 +54,6 @@ export interface IServiceConfig {
|
|||||||
*/
|
*/
|
||||||
replicationBaseEndpoint?: string;
|
replicationBaseEndpoint?: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* The base endpoint of the service used to handle the adapters.
|
|
||||||
*/
|
|
||||||
adapterEndpoint?: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base endpoint of the service used to handle the replication rules.
|
* The base endpoint of the service used to handle the replication rules.
|
||||||
* Replication rule related endpoints will be built based on this endpoint.
|
* Replication rule related endpoints will be built based on this endpoint.
|
||||||
|
@ -87,15 +87,17 @@ export interface Endpoint extends Base {
|
|||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Filter {
|
||||||
|
type: string;
|
||||||
|
style: string;
|
||||||
|
values ?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface Adapter extends Base {
|
export interface Adapter extends Base {
|
||||||
type: string;
|
type: string;
|
||||||
description: string;
|
description: string;
|
||||||
supported_resource_types: [
|
supported_triggers: string [];
|
||||||
string
|
supported_resource_filters: Filter [];
|
||||||
];
|
|
||||||
supported_resource_filters: [
|
|
||||||
string
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,7 @@ import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
|||||||
|
|
||||||
describe('JobLogService', () => {
|
describe('JobLogService', () => {
|
||||||
const mockConfig: IServiceConfig = {
|
const mockConfig: IServiceConfig = {
|
||||||
replicationBaseEndpoint: "/api/replication/executions/testing",
|
replicationBaseEndpoint: "/api/replication/testing",
|
||||||
scanJobEndpoint: "/api/jobs/scan/testing"
|
scanJobEndpoint: "/api/jobs/scan/testing"
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ describe('JobLogService', () => {
|
|||||||
|
|
||||||
it('should be initialized', inject([JobLogDefaultService], (service: JobLogService) => {
|
it('should be initialized', inject([JobLogDefaultService], (service: JobLogService) => {
|
||||||
expect(service).toBeTruthy();
|
expect(service).toBeTruthy();
|
||||||
expect(config.replicationBaseEndpoint).toEqual("/api/replication/executions/testing");
|
expect(config.replicationBaseEndpoint).toEqual("/api/replication/testing");
|
||||||
expect(config.scanJobEndpoint).toEqual("/api/jobs/scan/testing");
|
expect(config.scanJobEndpoint).toEqual("/api/jobs/scan/testing");
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,7 @@ export class JobLogDefaultService extends JobLogService {
|
|||||||
super();
|
super();
|
||||||
this._replicationJobBaseUrl = config.replicationBaseEndpoint
|
this._replicationJobBaseUrl = config.replicationBaseEndpoint
|
||||||
? config.replicationBaseEndpoint
|
? config.replicationBaseEndpoint
|
||||||
: "/api/replication/executions";
|
: "/api/replication";
|
||||||
this._scanningJobBaseUrl = config.scanJobEndpoint
|
this._scanningJobBaseUrl = config.scanJobEndpoint
|
||||||
? config.scanJobEndpoint
|
? config.scanJobEndpoint
|
||||||
: "/api/jobs/scan";
|
: "/api/jobs/scan";
|
||||||
|
@ -7,7 +7,7 @@ import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
|||||||
describe('ReplicationService', () => {
|
describe('ReplicationService', () => {
|
||||||
const mockConfig: IServiceConfig = {
|
const mockConfig: IServiceConfig = {
|
||||||
replicationRuleEndpoint: "/api/policies/replication/testing",
|
replicationRuleEndpoint: "/api/policies/replication/testing",
|
||||||
replicationBaseEndpoint: "/api/replication/executions/testing"
|
replicationBaseEndpoint: "/api/replication/testing"
|
||||||
};
|
};
|
||||||
|
|
||||||
let config: IServiceConfig;
|
let config: IServiceConfig;
|
||||||
@ -38,6 +38,6 @@ describe('ReplicationService', () => {
|
|||||||
it('should inject the right config', () => {
|
it('should inject the right config', () => {
|
||||||
expect(config).toBeTruthy();
|
expect(config).toBeTruthy();
|
||||||
expect(config.replicationRuleEndpoint).toEqual("/api/policies/replication/testing");
|
expect(config.replicationRuleEndpoint).toEqual("/api/policies/replication/testing");
|
||||||
expect(config.replicationBaseEndpoint).toEqual("/api/replication/executions/testing");
|
expect(config.replicationBaseEndpoint).toEqual("/api/replication/testing");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -10,7 +10,8 @@ import {
|
|||||||
ReplicationJob,
|
ReplicationJob,
|
||||||
ReplicationRule,
|
ReplicationRule,
|
||||||
ReplicationJobItem,
|
ReplicationJobItem,
|
||||||
ReplicationTasks
|
ReplicationTasks,
|
||||||
|
Adapter
|
||||||
} from "./interface";
|
} from "./interface";
|
||||||
import { RequestQueryParams } from "./RequestQueryParams";
|
import { RequestQueryParams } from "./RequestQueryParams";
|
||||||
import { map, catchError } from "rxjs/operators";
|
import { map, catchError } from "rxjs/operators";
|
||||||
@ -140,6 +141,9 @@ export abstract class ReplicationService {
|
|||||||
ruleId: number | string
|
ruleId: number | string
|
||||||
): Observable<any>;
|
): Observable<any>;
|
||||||
|
|
||||||
|
|
||||||
|
abstract getReplicationAdapter(type: string): Observable<Adapter>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the jobs for the specified replication rule.
|
* Get the jobs for the specified replication rule.
|
||||||
* Set query parameters through 'queryParams', support:
|
* Set query parameters through 'queryParams', support:
|
||||||
@ -202,7 +206,7 @@ export class ReplicationDefaultService extends ReplicationService {
|
|||||||
: "/api/replication/policies";
|
: "/api/replication/policies";
|
||||||
this._replicateUrl = config.replicationBaseEndpoint
|
this._replicateUrl = config.replicationBaseEndpoint
|
||||||
? config.replicationBaseEndpoint
|
? config.replicationBaseEndpoint
|
||||||
: "/api/replication/executions";
|
: "/api/replication";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private methods
|
// Private methods
|
||||||
@ -218,6 +222,14 @@ export class ReplicationDefaultService extends ReplicationService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getReplicationAdapter(type): Observable<Adapter> {
|
||||||
|
let requestUrl: string = `${this._replicateUrl}/adapters/${type}`;
|
||||||
|
return this.http
|
||||||
|
.get(requestUrl)
|
||||||
|
.pipe(map(response => response.json() as Adapter)
|
||||||
|
, catchError(error => observableThrowError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
public getJobBaseUrl() {
|
public getJobBaseUrl() {
|
||||||
return this._replicateUrl;
|
return this._replicateUrl;
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,8 @@ const uiLibConfig: IServiceConfig = {
|
|||||||
repositoryBaseEndpoint: "/api/repositories",
|
repositoryBaseEndpoint: "/api/repositories",
|
||||||
logBaseEndpoint: "/api/logs",
|
logBaseEndpoint: "/api/logs",
|
||||||
targetBaseEndpoint: "/api/registries",
|
targetBaseEndpoint: "/api/registries",
|
||||||
replicationBaseEndpoint: "/api/replication/executions",
|
replicationBaseEndpoint: "/api/replication",
|
||||||
replicationRuleEndpoint: "/api/replication/policies",
|
replicationRuleEndpoint: "/api/replication/policies",
|
||||||
adapterEndpoint: "api/replication/adapters",
|
|
||||||
vulnerabilityScanningBaseEndpoint: "/api/repositories",
|
vulnerabilityScanningBaseEndpoint: "/api/repositories",
|
||||||
projectPolicyEndpoint: "/api/projects/configs",
|
projectPolicyEndpoint: "/api/projects/configs",
|
||||||
projectBaseEndpoint: "/api/projects",
|
projectBaseEndpoint: "/api/projects",
|
||||||
|
Loading…
Reference in New Issue
Block a user