mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-29 20:18:05 +01:00
Merge pull request #8727 from AllForNothing/tag-retention-bug
fix bugs for tag-retention
This commit is contained in:
commit
c9f12bc273
@ -17,7 +17,7 @@
|
|||||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ "SCHEDULE.CRON" | translate }} :</span>
|
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ "SCHEDULE.CRON" | translate }} :</span>
|
||||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ oriCron }}</span>
|
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ oriCron }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary btn-sm" (click)="editSchedule()" id="editSchedule">
|
<button [disabled]="disabled" class="btn btn-primary btn-sm" (click)="editSchedule()" id="editSchedule">
|
||||||
{{ "BUTTON.EDIT" | translate }}
|
{{ "BUTTON.EDIT" | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,6 +27,7 @@ export class CronScheduleComponent implements OnChanges {
|
|||||||
@Input() originCron: OriginCron;
|
@Input() originCron: OriginCron;
|
||||||
@Input() labelEdit: string;
|
@Input() labelEdit: string;
|
||||||
@Input() labelCurrent: string;
|
@Input() labelCurrent: string;
|
||||||
|
@Input() disabled: boolean;
|
||||||
dateInvalid: boolean;
|
dateInvalid: boolean;
|
||||||
originScheduleType: string;
|
originScheduleType: string;
|
||||||
oriCron: string;
|
oriCron: string;
|
||||||
|
@ -68,7 +68,13 @@ export class AddRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set num(num) {
|
set num(num) {
|
||||||
this.rule.params[this.template] = parseInt(num, 10);
|
if (num) {
|
||||||
|
num = num.trim();
|
||||||
|
}
|
||||||
|
if (parseInt(num, 10) > 0) {
|
||||||
|
num = parseInt(num, 10);
|
||||||
|
}
|
||||||
|
this.rule.params[this.template] = num;
|
||||||
}
|
}
|
||||||
|
|
||||||
get repoSelect() {
|
get repoSelect() {
|
||||||
@ -128,8 +134,8 @@ export class AddRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canNotAdd(): boolean {
|
canNotAdd(): boolean {
|
||||||
if (!this.isAdd) {
|
if (!this.isAdd && compareValue(this.editRuleOrigin, this.rule)) {
|
||||||
return compareValue(this.editRuleOrigin, this.rule);
|
return true;
|
||||||
}
|
}
|
||||||
if (!this.hasParam()) {
|
if (!this.hasParam()) {
|
||||||
return !(this.rule.template
|
return !(this.rule.template
|
||||||
@ -138,6 +144,7 @@ export class AddRuleComponent implements OnInit, OnDestroy {
|
|||||||
} else {
|
} else {
|
||||||
return !(this.rule.template
|
return !(this.rule.template
|
||||||
&& this.rule.params[this.template]
|
&& this.rule.params[this.template]
|
||||||
|
&& parseInt(this.rule.params[this.template], 10) >= 0
|
||||||
&& this.rule.scope_selectors.repository[0].pattern
|
&& this.rule.scope_selectors.repository[0].pattern
|
||||||
&& this.rule.tag_selectors[0].pattern);
|
&& this.rule.tag_selectors[0].pattern);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ export class Retention {
|
|||||||
rules: Array<Rule>;
|
rules: Array<Rule>;
|
||||||
trigger: {
|
trigger: {
|
||||||
kind: string;
|
kind: string;
|
||||||
|
references: object;
|
||||||
settings: {
|
settings: {
|
||||||
cron: string;
|
cron: string;
|
||||||
}
|
}
|
||||||
@ -31,8 +32,9 @@ export class Retention {
|
|||||||
this.algorithm = "or";
|
this.algorithm = "or";
|
||||||
this.trigger = {
|
this.trigger = {
|
||||||
kind: "Schedule",
|
kind: "Schedule",
|
||||||
|
references: {},
|
||||||
settings: {
|
settings: {
|
||||||
cron: "0 0 0 * * *",
|
cron: "",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cron-selection">
|
<div class="cron-selection">
|
||||||
<cron-selection #cronScheduleComponent [labelCurrent]="label" [labelEdit]='label' [originCron]='originCron()' (inputvalue)="updateCron($event)"></cron-selection>
|
<cron-selection [disabled]="!(retention?.rules?.length > 0)" #cronScheduleComponent [labelCurrent]="label" [labelEdit]='label' [originCron]='originCron()' (inputvalue)="openConfirm($event)"></cron-selection>
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-row pt-1">
|
<div class="clr-row pt-1">
|
||||||
<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-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 padding-left-4">
|
||||||
<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"
|
||||||
(click)="isRetentionRunOpened=true">
|
(click)="isRetentionRunOpened=true">
|
||||||
@ -162,11 +162,21 @@
|
|||||||
<clr-modal [(clrModalOpen)]="isRetentionRunOpened"
|
<clr-modal [(clrModalOpen)]="isRetentionRunOpened"
|
||||||
[clrModalStaticBackdrop]="true" [clrModalClosable]="true">
|
[clrModalStaticBackdrop]="true" [clrModalClosable]="true">
|
||||||
<h3 class="modal-title">{{'TAG_RETENTION.RETENTION_RUN' | translate}}</h3>
|
<h3 class="modal-title">{{'TAG_RETENTION.RETENTION_RUN' | translate}}</h3>
|
||||||
<div class="modal-body">
|
<div class="modal-body pt-1">
|
||||||
<p class="color-97">
|
<div class="alert alert-danger" role="alert">
|
||||||
{{'TAG_RETENTION.RETENTION_RUN_EXPLAIN' | translate}}
|
<div class="alert-items">
|
||||||
</p>
|
<div class="alert-item static">
|
||||||
|
<div class="alert-icon-wrapper">
|
||||||
|
<clr-icon class="alert-icon" shape="exclamation-triangle"></clr-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="alert-text">
|
||||||
|
{{'TAG_RETENTION.RETENTION_RUN_EXPLAIN' | translate}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-outline"
|
<button type="button" class="btn btn-outline"
|
||||||
(click)="isRetentionRunOpened=false">{{'BUTTON.CANCEL' | translate}}</button>
|
(click)="isRetentionRunOpened=false">{{'BUTTON.CANCEL' | translate}}</button>
|
||||||
@ -184,4 +194,25 @@
|
|||||||
(click)="abortRetention()">{{'BUTTON.OK' | translate}}</button>
|
(click)="abortRetention()">{{'BUTTON.OK' | translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
</clr-modal>
|
</clr-modal>
|
||||||
|
<clr-modal [(clrModalOpen)]="isConfirmOpened"
|
||||||
|
[clrModalStaticBackdrop]="true" [clrModalClosable]="true">
|
||||||
|
<h3 class="modal-title">{{'TAG_RETENTION.SCHEDULE' | translate}}</h3>
|
||||||
|
<div class="modal-body pt-1">
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
<div class="alert-items">
|
||||||
|
<div class="alert-item static">
|
||||||
|
<div class="alert-icon-wrapper">
|
||||||
|
<clr-icon class="alert-icon" shape="exclamation-triangle"></clr-icon>
|
||||||
|
</div>
|
||||||
|
<span class="alert-text">
|
||||||
|
{{'TAG_RETENTION.SCHEDULE_WARNING' | translate}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" (click)="closeConfirm()" class="btn btn-primary">{{'BUTTON.OK' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</clr-modal>
|
||||||
<div class="backdrop-transparent" (click)="ruleIndex = -1" *ngIf="ruleIndex !== -1"></div>
|
<div class="backdrop-transparent" (click)="ruleIndex = -1" *ngIf="ruleIndex !== -1"></div>
|
@ -58,3 +58,6 @@
|
|||||||
.font-size-54 {
|
.font-size-54 {
|
||||||
font-size: .541667rem;
|
font-size: .541667rem;
|
||||||
}
|
}
|
||||||
|
.padding-left-4 {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
@ -58,6 +58,8 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
projectId: number;
|
projectId: number;
|
||||||
isRetentionRunOpened: boolean = false;
|
isRetentionRunOpened: boolean = false;
|
||||||
isAbortedOpened: boolean = false;
|
isAbortedOpened: boolean = false;
|
||||||
|
isConfirmOpened: boolean = false;
|
||||||
|
cron: string;
|
||||||
selectedItem: any = null;
|
selectedItem: any = null;
|
||||||
ruleIndex: number = -1;
|
ruleIndex: number = -1;
|
||||||
index: number = -1;
|
index: number = -1;
|
||||||
@ -84,8 +86,8 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
originCron(): OriginCron {
|
originCron(): OriginCron {
|
||||||
let originCron: OriginCron = {
|
let originCron: OriginCron = {
|
||||||
type: SCHEDULE_TYPE.DAILY,
|
type: SCHEDULE_TYPE.NONE,
|
||||||
cron: "0 0 0 * * *"
|
cron: ""
|
||||||
};
|
};
|
||||||
originCron.cron = this.retention.trigger.settings.cron;
|
originCron.cron = this.retention.trigger.settings.cron;
|
||||||
if (originCron.cron === "") {
|
if (originCron.cron === "") {
|
||||||
@ -118,6 +120,18 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.getRetention();
|
this.getRetention();
|
||||||
this.getMetadata();
|
this.getMetadata();
|
||||||
}
|
}
|
||||||
|
openConfirm(cron: string) {
|
||||||
|
if (cron) {
|
||||||
|
this.isConfirmOpened = true;
|
||||||
|
this.cron = cron;
|
||||||
|
} else {
|
||||||
|
this.updateCron(cron);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closeConfirm() {
|
||||||
|
this.isConfirmOpened = false;
|
||||||
|
this.updateCron(this.cron);
|
||||||
|
}
|
||||||
updateCron(cron: string) {
|
updateCron(cron: string) {
|
||||||
let retention: Retention = clone(this.retention);
|
let retention: Retention = clone(this.retention);
|
||||||
retention.trigger.settings.cron = cron;
|
retention.trigger.settings.cron = cron;
|
||||||
@ -133,7 +147,7 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.cronScheduleComponent.isEditMode = false;
|
this.cronScheduleComponent.isEditMode = false;
|
||||||
this.retention = retention;
|
this.getRetention();
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
@ -176,8 +190,7 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
this.loadingRule = true;
|
this.loadingRule = true;
|
||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.loadingRule = false;
|
this.getRetention();
|
||||||
this.retention = retention;
|
|
||||||
}, error => {
|
}, error => {
|
||||||
this.loadingRule = false;
|
this.loadingRule = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
@ -186,12 +199,15 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
deleteRule(index) {
|
deleteRule(index) {
|
||||||
let retention: Retention = clone(this.retention);
|
let retention: Retention = clone(this.retention);
|
||||||
retention.rules.splice(index, 1);
|
retention.rules.splice(index, 1);
|
||||||
|
// if rules is empty, clear schedule.
|
||||||
|
if (retention.rules && retention.rules.length === 0) {
|
||||||
|
retention.trigger.settings.cron = "";
|
||||||
|
}
|
||||||
this.ruleIndex = -1;
|
this.ruleIndex = -1;
|
||||||
this.loadingRule = true;
|
this.loadingRule = true;
|
||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.loadingRule = false;
|
this.getRetention();
|
||||||
this.retention = retention;
|
|
||||||
}, error => {
|
}, error => {
|
||||||
this.loadingRule = false;
|
this.loadingRule = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
@ -340,8 +356,7 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.loadingRule = false;
|
this.getRetention();
|
||||||
this.retention = retention;
|
|
||||||
}, error => {
|
}, error => {
|
||||||
this.loadingRule = false;
|
this.loadingRule = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
@ -352,8 +367,7 @@ export class TagRetentionComponent implements OnInit {
|
|||||||
retention.rules[this.editIndex] = rule;
|
retention.rules[this.editIndex] = rule;
|
||||||
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
this.tagRetentionService.updateRetention(this.retentionId, retention).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.retention = retention;
|
this.getRetention();
|
||||||
this.loadingRule = false;
|
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
this.loadingRule = false;
|
this.loadingRule = false;
|
||||||
|
@ -28,8 +28,8 @@ export class TagRetentionService {
|
|||||||
"latestPushedK": "RULE_NAME_3",
|
"latestPushedK": "RULE_NAME_3",
|
||||||
"latestPulledN": "RULE_NAME_4",
|
"latestPulledN": "RULE_NAME_4",
|
||||||
"always": "RULE_NAME_5",
|
"always": "RULE_NAME_5",
|
||||||
"dayspl": "RULE_NAME_6",
|
"nDaysSinceLastPull": "RULE_NAME_6",
|
||||||
"daysps": "RULE_NAME_7",
|
"nDaysSinceLastPush": "RULE_NAME_7",
|
||||||
"the images from the last # days": "RULE_TEMPLATE_1",
|
"the images from the last # days": "RULE_TEMPLATE_1",
|
||||||
"the most recent active # images": "RULE_TEMPLATE_2",
|
"the most recent active # images": "RULE_TEMPLATE_2",
|
||||||
"the most recently pushed # images": "RULE_TEMPLATE_3",
|
"the most recently pushed # images": "RULE_TEMPLATE_3",
|
||||||
|
@ -1206,7 +1206,9 @@
|
|||||||
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
||||||
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
||||||
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
||||||
"RULE_TEMPLATE_7": " the images pushed within the last # days"
|
"RULE_TEMPLATE_7": " the images pushed within the last # days",
|
||||||
|
"SCHEDULE": "Schedule",
|
||||||
|
"SCHEDULE_WARNING": "Executing the retention policy can have adverse effects to the images in this project and affected image tags will be deleted."
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1203,7 +1203,9 @@
|
|||||||
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
||||||
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
||||||
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
||||||
"RULE_TEMPLATE_7": " the images pushed within the last # days"
|
"RULE_TEMPLATE_7": " the images pushed within the last # days",
|
||||||
|
"SCHEDULE": "Schedule",
|
||||||
|
"SCHEDULE_WARNING": "Executing the retention policy can have adverse effects to the images in this project and affected image tags will be deleted."
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1175,7 +1175,9 @@
|
|||||||
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
||||||
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
||||||
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
||||||
"RULE_TEMPLATE_7": " the images pushed within the last # days"
|
"RULE_TEMPLATE_7": " the images pushed within the last # days",
|
||||||
|
"SCHEDULE": "Schedule",
|
||||||
|
"SCHEDULE_WARNING": "Executing the retention policy can have adverse effects to the images in this project and affected image tags will be deleted."
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1200,7 +1200,9 @@
|
|||||||
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
"RULE_NAME_6": " the images pulled within the last {{number}} days",
|
||||||
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
"RULE_NAME_7": " the images pushed within the last {{number}} days",
|
||||||
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
"RULE_TEMPLATE_6": " the images pulled within the last # days",
|
||||||
"RULE_TEMPLATE_7": " the images pushed within the last # days"
|
"RULE_TEMPLATE_7": " the images pushed within the last # days",
|
||||||
|
"SCHEDULE": "Schedule",
|
||||||
|
"SCHEDULE_WARNING": "Executing the retention policy can have adverse effects to the images in this project and affected image tags will be deleted."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1202,7 +1202,9 @@
|
|||||||
"RULE_NAME_6": "最近{{number}}天被拉取过的镜像",
|
"RULE_NAME_6": "最近{{number}}天被拉取过的镜像",
|
||||||
"RULE_NAME_7": "最近{{number}}天被推送过的镜像",
|
"RULE_NAME_7": "最近{{number}}天被推送过的镜像",
|
||||||
"RULE_TEMPLATE_6": "最近#天被拉取过的镜像",
|
"RULE_TEMPLATE_6": "最近#天被拉取过的镜像",
|
||||||
"RULE_TEMPLATE_7": "最近#天被推送过的镜像"
|
"RULE_TEMPLATE_7": "最近#天被推送过的镜像",
|
||||||
|
"SCHEDULE": "定时任务",
|
||||||
|
"SCHEDULE_WARNING": "执行保留策略将对该项目中的镜像产生反向影响,受影响的镜像tags将会被删除。"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user