mirror of
https://github.com/goharbor/harbor
synced 2025-05-18 19:58:06 +00:00
Merge pull request #8492 from AllForNothing/opt
Optimization for tag-retention UI
This commit is contained in:
commit
ec30def94b
@ -3,6 +3,8 @@ import { Type } from "@angular/core";
|
|||||||
import { CronScheduleComponent } from "./cron-schedule.component";
|
import { CronScheduleComponent } from "./cron-schedule.component";
|
||||||
import { CronTooltipComponent } from "./cron-tooltip/cron-tooltip.component";
|
import { CronTooltipComponent } from "./cron-tooltip/cron-tooltip.component";
|
||||||
|
|
||||||
|
export * from "./cron-schedule.component";
|
||||||
|
export * from './cron-tooltip/cron-tooltip.component';
|
||||||
export const CRON_SCHEDULE_DIRECTIVES: Type<any>[] = [
|
export const CRON_SCHEDULE_DIRECTIVES: Type<any>[] = [
|
||||||
CronScheduleComponent,
|
CronScheduleComponent,
|
||||||
CronTooltipComponent
|
CronTooltipComponent
|
||||||
|
@ -27,4 +27,5 @@ export * from "./gridview/index";
|
|||||||
export * from "./repository-gridview/index";
|
export * from "./repository-gridview/index";
|
||||||
export * from "./operation/index";
|
export * from "./operation/index";
|
||||||
export * from "./_animations/index";
|
export * from "./_animations/index";
|
||||||
|
export * from "./cron-schedule/index";
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ export class Retention {
|
|||||||
this.trigger = {
|
this.trigger = {
|
||||||
kind: "Schedule",
|
kind: "Schedule",
|
||||||
settings: {
|
settings: {
|
||||||
cron: "@daily",
|
cron: "0 0 0 * * *",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<div class="clr-row pt-1 fw8">
|
<div class="clr-row pt-1 fw8">
|
||||||
<div class="clr-col-2">
|
<div class="clr-col">
|
||||||
<label class="fw9-l">{{'TAG_RETENTION.RETENTION_RULES' | translate}}</label><span
|
<label class="label-left font-size-54">{{'TAG_RETENTION.RETENTION_RULES' | translate}}</label><span
|
||||||
class="badge badge-3 clr-offset-1">{{retention?.rules?.length ? retention?.rules?.length : 0}}</span>
|
class="badge badge-3 ml-5">{{retention?.rules?.length ? retention?.rules?.length : 0}}</span>
|
||||||
|
<span *ngIf="loadingRule" class="spinner spinner-inline ml-2">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-row pt-1">
|
<div class="clr-row pt-1">
|
||||||
<div class="clr-col">
|
<div class="clr-col">
|
||||||
@ -45,14 +45,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clr-row pt-1">
|
<div class="v-center clr-row pt-1">
|
||||||
<div class="clr-col-5 color-97">
|
<div class="clr-col-5 color-97 font-size-54">
|
||||||
<div>
|
{{'TAG_RETENTION.ADD_RULE_HELP_1' | translate}}
|
||||||
<span>{{'TAG_RETENTION.ADD_RULE_HELP_1' | translate}}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>{{'TAG_RETENTION.ADD_RULE_HELP_2' | translate}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col">
|
<div class="clr-col">
|
||||||
<button class="btn btn-link" (click)="openAddRule()">{{'TAG_RETENTION.ADD_RULE' | translate}}</button>
|
<button class="btn btn-link" (click)="openAddRule()">{{'TAG_RETENTION.ADD_RULE' | translate}}</button>
|
||||||
@ -60,8 +55,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="cron-selection">
|
||||||
|
<cron-selection #cronScheduleComponent [labelCurrent]="label" [labelEdit]='label' [originCron]='originCron()' (inputvalue)="updateCron($event)"></cron-selection>
|
||||||
|
</div>
|
||||||
<div class="clr-row pt-1">
|
<div class="clr-row pt-1">
|
||||||
<div class="clr-col-2 pt-2"><label class="fw9-l">{{'TAG_RETENTION.RETENTION_RUNS' | translate}}</label></div>
|
<div class="clr-col-2 pt-2"><label class="label-left font-size-54">{{'TAG_RETENTION.RETENTION_RUNS' | translate}}</label></div>
|
||||||
<div class="clr-col-10">
|
<div class="clr-col-10">
|
||||||
<clr-dg-action-bar>
|
<clr-dg-action-bar>
|
||||||
<button [disabled]="!(retention?.rules?.length > 0)" class="btn btn-outline"
|
<button [disabled]="!(retention?.rules?.length > 0)" class="btn btn-outline"
|
||||||
@ -71,7 +69,9 @@
|
|||||||
<button [disabled]="!(retention?.rules?.length > 0)" class="btn btn-outline"
|
<button [disabled]="!(retention?.rules?.length > 0)" class="btn btn-outline"
|
||||||
(click)="whatIfRun()">{{'TAG_RETENTION.WHAT_IF_RUN' | translate}}</button>
|
(click)="whatIfRun()">{{'TAG_RETENTION.WHAT_IF_RUN' | translate}}</button>
|
||||||
<button [disabled]="!(selectedItem && (selectedItem.status ==='InProgress' || selectedItem.status ==='Running'))"
|
<button [disabled]="!(selectedItem && (selectedItem.status ==='InProgress' || selectedItem.status ==='Running'))"
|
||||||
class="btn btn-outline" (click)="abortRun()">{{'TAG_RETENTION.ABORT' | translate}}</button>
|
class="btn btn-outline" (click)="abortRun()">
|
||||||
|
<clr-icon shape="stop"></clr-icon>
|
||||||
|
<span class="ml-5">{{'TAG_RETENTION.ABORT' | translate}}</span></button>
|
||||||
<button [disabled]="!retentionId" class="btn btn-outline"
|
<button [disabled]="!retentionId" class="btn btn-outline"
|
||||||
(click)="refreshList()">
|
(click)="refreshList()">
|
||||||
<clr-icon shape="refresh"></clr-icon>
|
<clr-icon shape="refresh"></clr-icon>
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
font-size: 0.6rem;
|
font-size: .541667rem;
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ml-5 {
|
.ml-5 {
|
||||||
@ -43,4 +42,19 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
}
|
||||||
|
.cron-selection {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.label-left {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.v-center {
|
||||||
|
height: 48px;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
.font-size-54 {
|
||||||
|
font-size: .541667rem;
|
||||||
}
|
}
|
@ -19,12 +19,20 @@ import { TagRetentionService } from "./tag-retention.service";
|
|||||||
import { Retention, Rule } from "./retention";
|
import { Retention, Rule } from "./retention";
|
||||||
import { Project } from "../project";
|
import { Project } from "../project";
|
||||||
import { clone, ErrorHandler } from "@harbor/ui";
|
import { clone, ErrorHandler } from "@harbor/ui";
|
||||||
|
import { OriginCron } from "@harbor/ui";
|
||||||
|
import { CronScheduleComponent } from "@harbor/ui";
|
||||||
|
|
||||||
const MIN = 60000;
|
const MIN = 60000;
|
||||||
const SEC = 1000;
|
const SEC = 1000;
|
||||||
const MIN_STR = "min";
|
const MIN_STR = "min";
|
||||||
const SEC_STR = "sec";
|
const SEC_STR = "sec";
|
||||||
|
const SCHEDULE_TYPE = {
|
||||||
|
NONE: "None",
|
||||||
|
DAILY: "Daily",
|
||||||
|
WEEKLY: "Weekly",
|
||||||
|
HOURLY: "Hourly",
|
||||||
|
CUSTOM: "Custom"
|
||||||
|
};
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tag-retention',
|
selector: 'tag-retention',
|
||||||
templateUrl: './tag-retention.component.html',
|
templateUrl: './tag-retention.component.html',
|
||||||
@ -48,7 +56,6 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
projectId: number;
|
projectId: number;
|
||||||
addRuleOpened: boolean = false;
|
|
||||||
isRetentionRunOpened: boolean = false;
|
isRetentionRunOpened: boolean = false;
|
||||||
isAbortedOpened: boolean = false;
|
isAbortedOpened: boolean = false;
|
||||||
selectedItem: any;
|
selectedItem: any;
|
||||||
@ -61,15 +68,36 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
historyList = [];
|
historyList = [];
|
||||||
loadingExecutions: boolean = false;
|
loadingExecutions: boolean = false;
|
||||||
loadingHistories: boolean = false;
|
loadingHistories: boolean = false;
|
||||||
dryRun: boolean = false;
|
label: string = 'TAG_RETENTION.TRIGGER';
|
||||||
|
loadingRule: boolean = false;
|
||||||
|
@ViewChild('cronScheduleComponent')
|
||||||
|
cronScheduleComponent: CronScheduleComponent;
|
||||||
@ViewChild('addRule') addRuleComponent: AddRuleComponent;
|
@ViewChild('addRule') addRuleComponent: AddRuleComponent;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private tagRetentionService: TagRetentionService,
|
private tagRetentionService: TagRetentionService,
|
||||||
private errorHandler: ErrorHandler,
|
private errorHandler: ErrorHandler,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
originCron(): OriginCron {
|
||||||
|
let originCron: OriginCron = {
|
||||||
|
type: SCHEDULE_TYPE.DAILY,
|
||||||
|
cron: "0 0 0 * * *"
|
||||||
|
};
|
||||||
|
originCron.cron = this.retention.trigger.settings.cron;
|
||||||
|
if (originCron.cron === "") {
|
||||||
|
originCron.type = SCHEDULE_TYPE.NONE;
|
||||||
|
} else if (originCron.cron === "0 0 * * * *") {
|
||||||
|
originCron.type = SCHEDULE_TYPE.HOURLY;
|
||||||
|
} else if (originCron.cron === "0 0 0 * * *") {
|
||||||
|
originCron.type = SCHEDULE_TYPE.DAILY;
|
||||||
|
} else if (originCron.cron === "0 0 0 * * 0") {
|
||||||
|
originCron.type = SCHEDULE_TYPE.WEEKLY;
|
||||||
|
} else {
|
||||||
|
originCron.type = SCHEDULE_TYPE.CUSTOM;
|
||||||
|
}
|
||||||
|
return originCron;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.projectId = +this.route.snapshot.parent.params['id'];
|
this.projectId = +this.route.snapshot.parent.params['id'];
|
||||||
@ -88,7 +116,27 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.getMetadata();
|
this.getMetadata();
|
||||||
this.refreshList();
|
this.refreshList();
|
||||||
}
|
}
|
||||||
|
updateCron(cron: string) {
|
||||||
|
let retention: Retention = clone(this.retention);
|
||||||
|
retention.trigger.settings.cron = cron;
|
||||||
|
if (!this.retentionId) {
|
||||||
|
this.tagRetentionService.createRetention(retention).subscribe(
|
||||||
|
response => {
|
||||||
|
this.cronScheduleComponent.isEditMode = false;
|
||||||
|
this.refreshAfterCreatRetention();
|
||||||
|
}, error => {
|
||||||
|
this.errorHandler.error(error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
|
response => {
|
||||||
|
this.cronScheduleComponent.isEditMode = false;
|
||||||
|
this.retention = retention;
|
||||||
|
}, error => {
|
||||||
|
this.errorHandler.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
getMetadata() {
|
getMetadata() {
|
||||||
this.tagRetentionService.getRetentionMetadata().subscribe(
|
this.tagRetentionService.getRetentionMetadata().subscribe(
|
||||||
response => {
|
response => {
|
||||||
@ -103,8 +151,10 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.tagRetentionService.getRetention(this.retentionId).subscribe(
|
this.tagRetentionService.getRetention(this.retentionId).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.retention = response;
|
this.retention = response;
|
||||||
|
this.loadingRule = false;
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
|
this.loadingRule = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,10 +172,13 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
let retention: Retention = clone(this.retention);
|
let retention: Retention = clone(this.retention);
|
||||||
retention.rules.splice(index, 1);
|
retention.rules.splice(index, 1);
|
||||||
this.ruleIndex = -1;
|
this.ruleIndex = -1;
|
||||||
|
this.loadingRule = true;
|
||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
|
this.loadingRule = false;
|
||||||
this.retention = retention;
|
this.retention = retention;
|
||||||
}, error => {
|
}, error => {
|
||||||
|
this.loadingRule = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -241,11 +294,13 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.retentionId = response.metadata.retention_id;
|
this.retentionId = response.metadata.retention_id;
|
||||||
this.getRetention();
|
this.getRetention();
|
||||||
}, error => {
|
}, error => {
|
||||||
|
this.loadingRule = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
clickAdd(rule) {
|
clickAdd(rule) {
|
||||||
|
this.loadingRule = true;
|
||||||
if (this.addRuleComponent.isAdd) {
|
if (this.addRuleComponent.isAdd) {
|
||||||
let retention: Retention = clone(this.retention);
|
let retention: Retention = clone(this.retention);
|
||||||
retention.rules.push(rule);
|
retention.rules.push(rule);
|
||||||
@ -255,12 +310,15 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.refreshAfterCreatRetention();
|
this.refreshAfterCreatRetention();
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
|
this.loadingRule = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
|
this.loadingRule = false;
|
||||||
this.retention = retention;
|
this.retention = retention;
|
||||||
}, error => {
|
}, error => {
|
||||||
|
this.loadingRule = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -270,8 +328,10 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.retention = retention;
|
this.retention = retention;
|
||||||
|
this.loadingRule = false;
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
|
this.loadingRule = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1161,7 +1161,8 @@
|
|||||||
"WITHOUT": " without ",
|
"WITHOUT": " without ",
|
||||||
"LOWER_LABELS": " labels",
|
"LOWER_LABELS": " labels",
|
||||||
"WITH_CONDITION": " with",
|
"WITH_CONDITION": " with",
|
||||||
"LOWER_TAGS": " tags"
|
"LOWER_TAGS": " tags",
|
||||||
|
"TRIGGER": "Schedule"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1159,7 +1159,8 @@
|
|||||||
"WITHOUT": " without ",
|
"WITHOUT": " without ",
|
||||||
"LOWER_LABELS": " labels",
|
"LOWER_LABELS": " labels",
|
||||||
"WITH_CONDITION": " with",
|
"WITH_CONDITION": " with",
|
||||||
"LOWER_TAGS": " tags"
|
"LOWER_TAGS": " tags",
|
||||||
|
"TRIGGER": "Schedule"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1131,7 +1131,8 @@
|
|||||||
"WITHOUT": " without ",
|
"WITHOUT": " without ",
|
||||||
"LOWER_LABELS": " labels",
|
"LOWER_LABELS": " labels",
|
||||||
"WITH_CONDITION": " with",
|
"WITH_CONDITION": " with",
|
||||||
"LOWER_TAGS": " tags"
|
"LOWER_TAGS": " tags",
|
||||||
|
"TRIGGER": "Schedule"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1156,7 +1156,8 @@
|
|||||||
"WITHOUT": " without ",
|
"WITHOUT": " without ",
|
||||||
"LOWER_LABELS": " labels",
|
"LOWER_LABELS": " labels",
|
||||||
"WITH_CONDITION": " with",
|
"WITH_CONDITION": " with",
|
||||||
"LOWER_TAGS": " tags"
|
"LOWER_TAGS": " tags",
|
||||||
|
"TRIGGER": "Schedule"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1157,7 +1157,8 @@
|
|||||||
"WITHOUT": "没有",
|
"WITHOUT": "没有",
|
||||||
"LOWER_LABELS": "标签",
|
"LOWER_LABELS": "标签",
|
||||||
"WITH_CONDITION": "基于条件",
|
"WITH_CONDITION": "基于条件",
|
||||||
"LOWER_TAGS": "tags"
|
"LOWER_TAGS": "tags",
|
||||||
|
"TRIGGER": "定时执行"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user