Merge pull request #8727 from AllForNothing/tag-retention-bug

fix bugs for tag-retention
This commit is contained in:
Will Sun 2019-08-20 10:46:53 +08:00 committed by GitHub
commit c9f12bc273
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 99 additions and 31 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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);
} }

View File

@ -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: "",
} }
}; };
} }

View File

@ -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>
<span class="alert-text">
{{'TAG_RETENTION.RETENTION_RUN_EXPLAIN' | translate}}
</span>
</div>
</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>
@ -174,7 +184,7 @@
</div> </div>
</clr-modal> </clr-modal>
<clr-modal [(clrModalOpen)]="isAbortedOpened" <clr-modal [(clrModalOpen)]="isAbortedOpened"
[clrModalStaticBackdrop]="true" [clrModalClosable]="true"> [clrModalStaticBackdrop]="true" [clrModalClosable]="true">
<h3 class="modal-title">{{'TAG_RETENTION.RETENTION_RUN_ABORTED' | translate}}</h3> <h3 class="modal-title">{{'TAG_RETENTION.RETENTION_RUN_ABORTED' | translate}}</h3>
<div class="modal-body"> <div class="modal-body">
<p class="color-97">{{'TAG_RETENTION.RETENTION_RUN_ABORTED_EXPLAIN' | translate}}</p> <p class="color-97">{{'TAG_RETENTION.RETENTION_RUN_ABORTED_EXPLAIN' | translate}}</p>
@ -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>

View File

@ -57,4 +57,7 @@
} }
.font-size-54 { .font-size-54 {
font-size: .541667rem; font-size: .541667rem;
}
.padding-left-4 {
padding-left: 4px;
} }

View File

@ -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);
}); });
@ -169,15 +183,14 @@ export class TagRetentionComponent implements OnInit {
this.addRuleComponent.isAdd = false; this.addRuleComponent.isAdd = false;
this.ruleIndex = -1; this.ruleIndex = -1;
} }
toggleDisable(index, isActionDisable) { toggleDisable(index, isActionDisable) {
let retention: Retention = clone(this.retention); let retention: Retention = clone(this.retention);
retention.rules[index].disabled = isActionDisable; retention.rules[index].disabled = isActionDisable;
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);
@ -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;

View File

@ -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",

View File

@ -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."
} }
} }

View File

@ -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."
} }
} }

View File

@ -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."
} }
} }

View File

@ -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."
} }

View File

@ -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将会被删除。"
} }
} }