mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-23 09:08:26 +01:00
Merge pull request #7083 from pureshine/support-cron
Refactoring gc ui support cron
This commit is contained in:
commit
41f443d3e3
@ -1,33 +1,5 @@
|
||||
<div class="normal-wrapper flex-layout" *ngIf="!isEditMode">
|
||||
<span class="font-style">{{'GC.CURRENT_SCHEDULE' | translate}}</span>
|
||||
<span>{{(originScheduleType ? 'SCHEDULE.'+ originScheduleType.toUpperCase(): "") | translate}}</span>
|
||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.WEEKLY">{{'SCHEDULE.ON' | translate}}</span>
|
||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.WEEKLY">{{originWeekDay.text | translate}}</span>
|
||||
<span [hidden]="originScheduleType===SCHEDULE_TYPE.NONE">{{'SCHEDULE.AT' | translate}}</span>
|
||||
<span [hidden]="originScheduleType===SCHEDULE_TYPE.NONE">{{originOffTime.text}} AM</span>
|
||||
<button class="btn btn-outline btn-sm" (click)="editSchedule()">{{'BUTTON.EDIT' | translate}}</button>
|
||||
</div>
|
||||
<div class="setting-wrapper flex-layout" *ngIf="isEditMode">
|
||||
<label for="gcPolicy" class="font-style">{{'CONFIG.GC' | translate}}</label>
|
||||
<div class="select">
|
||||
<select id="gcPolicy" name="gcPolicy" [(ngModel)]="scheduleType">
|
||||
<option [value]="SCHEDULE_TYPE.NONE">{{'SCHEDULE.NONE' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.DAILY">{{'SCHEDULE.DAILY' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.WEEKLY">{{'SCHEDULE.WEEKLY' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<section [hidden]="scheduleType!== SCHEDULE_TYPE.WEEKLY" class="select day-selector-wrapper">
|
||||
<span>{{'SCHEDULE.ON' | translate}}</span>
|
||||
<select id="daySelector" name="daySelector" [(ngModel)]="weekDay">
|
||||
<option *ngFor="let d of weekDays" [ngValue]="d">{{d.text | translate}}</option>
|
||||
</select>
|
||||
</section>
|
||||
<section [hidden]="scheduleType===SCHEDULE_TYPE.NONE">
|
||||
<span>{{'SCHEDULE.AT' | translate}}</span>
|
||||
<input type="time" name="dailyTimePicker" required [(ngModel)]="dailyTime" />
|
||||
</section>
|
||||
<button class="btn btn-primary btn-sm" (click)="scheduleGc()">{{'BUTTON.SAVE' | translate}}</button>
|
||||
<button class="btn btn-primary btn-sm" (click)="isEditMode = false" >{{'BUTTON.CANCEL' | translate}}</button>
|
||||
<div class="cron-selection">
|
||||
<cron-selection [labelCurrent]="getLabelCurrent" [labelEdit]='getText' [originCron]='originCron' (inputvalue)="getcron($event)"></cron-selection>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm gc-start-btn" (click)="gcNow()" [disabled]="disableGC">{{'GC.GC_NOW' | translate}}</button>
|
||||
<div class="job-header font-style">{{'GC.JOB_HISTORY' | translate}}</div>
|
||||
|
@ -10,6 +10,10 @@
|
||||
font-size: .541667rem;
|
||||
}
|
||||
|
||||
.cron-selection {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.setting-wrapper {
|
||||
label {
|
||||
width: 228px;
|
||||
|
@ -6,7 +6,7 @@ import { GcRepoService } from './gc.service';
|
||||
import { SharedModule } from "../../shared/shared.module";
|
||||
import { ErrorHandler } from '../../error-handler/error-handler';
|
||||
import { GcViewModelFactory } from './gc.viewmodel.factory';
|
||||
import { GcUtility } from './gc.utility';
|
||||
import { CronScheduleComponent } from '../../cron-schedule/cron-schedule.component';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('GcComponent', () => {
|
||||
@ -33,14 +33,13 @@ describe('GcComponent', () => {
|
||||
imports: [
|
||||
SharedModule
|
||||
],
|
||||
declarations: [ GcComponent ],
|
||||
declarations: [ GcComponent, CronScheduleComponent],
|
||||
providers: [
|
||||
{ provide: GcApiRepository, useClass: GcApiDefaultRepository },
|
||||
{ provide: SERVICE_CONFIG, useValue: config },
|
||||
GcRepoService,
|
||||
ErrorHandler,
|
||||
GcViewModelFactory,
|
||||
GcUtility
|
||||
GcViewModelFactory
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
@ -1,40 +1,47 @@
|
||||
import { Component, Input, Output, EventEmitter, ViewChild, OnInit } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { GcJobViewModel, WeekDay } from "./gcLog";
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
ViewChild,
|
||||
OnInit
|
||||
} from "@angular/core";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { GcJobViewModel } from "./gcLog";
|
||||
import { GcViewModelFactory } from "./gc.viewmodel.factory";
|
||||
import { GcRepoService } from "./gc.service";
|
||||
import { WEEKDAYS, SCHEDULE_TYPE, ONE_MINITUE, THREE_SECONDS} from './gc.const';
|
||||
import { GcUtility } from './gc.utility';
|
||||
import { ErrorHandler } from '../../error-handler/index';
|
||||
import {
|
||||
SCHEDULE_TYPE_NONE,
|
||||
ONE_MINITUE,
|
||||
THREE_SECONDS
|
||||
} from "./gc.const";
|
||||
import { ErrorHandler } from "../../error-handler/index";
|
||||
import { CronScheduleComponent } from "../../cron-schedule/cron-schedule.component";
|
||||
import { OriginCron } from '../../service/interface';
|
||||
|
||||
@Component({
|
||||
selector: 'gc-config',
|
||||
templateUrl: './gc.component.html',
|
||||
styleUrls: ['./gc.component.scss']
|
||||
selector: "gc-config",
|
||||
templateUrl: "./gc.component.html",
|
||||
styleUrls: ["./gc.component.scss"]
|
||||
})
|
||||
export class GcComponent implements OnInit {
|
||||
jobs: Array<GcJobViewModel> = [];
|
||||
schedule: any;
|
||||
originScheduleType: string;
|
||||
originOffTime: any = { value: null, text: "" };
|
||||
originWeekDay: any = { value: null, text: "" };
|
||||
scheduleType: string;
|
||||
isEditMode: boolean = false;
|
||||
weekDays = WEEKDAYS;
|
||||
SCHEDULE_TYPE = SCHEDULE_TYPE;
|
||||
weekDay: WeekDay = WEEKDAYS[0];
|
||||
dailyTime: string;
|
||||
originCron: OriginCron;
|
||||
disableGC: boolean = false;
|
||||
|
||||
constructor(private gcRepoService: GcRepoService,
|
||||
getText = 'CONFIG.GC';
|
||||
getLabelCurrent = 'GC.CURRENT_SCHEDULE';
|
||||
@ViewChild(CronScheduleComponent)
|
||||
CronScheduleComponent: CronScheduleComponent;
|
||||
constructor(
|
||||
private gcRepoService: GcRepoService,
|
||||
private gcViewModelFactory: GcViewModelFactory,
|
||||
private gcUtility: GcUtility,
|
||||
private errorHandler: ErrorHandler,
|
||||
private translate: TranslateService) {
|
||||
translate.setDefaultLang('en-us');
|
||||
private translate: TranslateService
|
||||
) {
|
||||
translate.setDefaultLang("en-us");
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.getCurrentSchedule();
|
||||
this.getJobs();
|
||||
@ -46,32 +53,15 @@ export class GcComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private initSchedule(schedule: any) {
|
||||
public initSchedule(schedule: any) {
|
||||
if (schedule && schedule.length > 0) {
|
||||
this.schedule = schedule[0];
|
||||
const cron = this.schedule.schedule;
|
||||
this.originScheduleType = cron.type;
|
||||
this.originWeekDay = this.weekDays[cron.weekday];
|
||||
let dailyTime = this.gcUtility.getDailyTime(cron.offtime);
|
||||
this.originOffTime = { value: cron.offtime, text: dailyTime };
|
||||
this.originCron = this.schedule.schedule;
|
||||
} else {
|
||||
this.originScheduleType = SCHEDULE_TYPE.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
editSchedule() {
|
||||
this.isEditMode = true;
|
||||
this.scheduleType = this.originScheduleType;
|
||||
if (this.originWeekDay.value) {
|
||||
this.weekDay = this.originWeekDay;
|
||||
} else {
|
||||
this.weekDay = this.weekDays[0];
|
||||
}
|
||||
|
||||
if (this.originOffTime.value) {
|
||||
this.dailyTime = this.originOffTime.text;
|
||||
} else {
|
||||
this.dailyTime = "00:00";
|
||||
this.originCron = {
|
||||
type: SCHEDULE_TYPE_NONE,
|
||||
cron: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,59 +73,58 @@ export class GcComponent implements OnInit {
|
||||
|
||||
gcNow(): void {
|
||||
this.disableGC = true;
|
||||
setTimeout(() => {this.enableGc(); }, ONE_MINITUE);
|
||||
setTimeout(() => {
|
||||
this.enableGc();
|
||||
}, ONE_MINITUE);
|
||||
|
||||
this.gcRepoService.manualGc().subscribe(response => {
|
||||
this.translate.get('GC.MSG_SUCCESS').subscribe((res: string) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
this.getJobs();
|
||||
setTimeout(() => {this.getJobs(); }, THREE_SECONDS); // to avoid some jobs not finished.
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
this.gcRepoService.manualGc().subscribe(
|
||||
response => {
|
||||
this.translate.get("GC.MSG_SUCCESS").subscribe((res: string) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
this.getJobs();
|
||||
setTimeout(() => {
|
||||
this.getJobs();
|
||||
}, THREE_SECONDS); // to avoid some jobs not finished.
|
||||
},
|
||||
error => {
|
||||
this.errorHandler.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private enableGc () {
|
||||
private enableGc() {
|
||||
this.disableGC = false;
|
||||
}
|
||||
|
||||
private resetSchedule(offTime) {
|
||||
this.schedule = {
|
||||
schedule: {
|
||||
type: this.scheduleType,
|
||||
offTime: offTime,
|
||||
weekDay: this.weekDay.value
|
||||
}
|
||||
};
|
||||
this.originScheduleType = this.scheduleType;
|
||||
this.originWeekDay = this.weekDay;
|
||||
this.originOffTime = { value: offTime, text: this.dailyTime };
|
||||
this.isEditMode = false;
|
||||
this.getJobs();
|
||||
}
|
||||
|
||||
scheduleGc(): void {
|
||||
let offTime = this.gcUtility.getOffTime(this.dailyTime);
|
||||
getcron(cron: string) {
|
||||
let schedule = this.schedule;
|
||||
if (schedule && schedule.schedule && schedule.schedule.type !== SCHEDULE_TYPE.NONE) {
|
||||
this.gcRepoService.putScheduleGc(this.scheduleType, offTime, this.weekDay.value).subscribe(response => {
|
||||
this.translate.get('GC.MSG_SCHEDULE_RESET').subscribe((res: string) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
this.resetSchedule(offTime);
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
if (schedule && schedule.schedule && schedule.schedule.type !== SCHEDULE_TYPE_NONE) {
|
||||
this.gcRepoService.putScheduleGc(this.CronScheduleComponent.scheduleType, cron).subscribe(
|
||||
response => {
|
||||
this.translate
|
||||
.get("GC.MSG_SCHEDULE_RESET")
|
||||
.subscribe((res) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
this.getJobs();
|
||||
},
|
||||
error => {
|
||||
this.errorHandler.error(error);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.gcRepoService.postScheduleGc(this.scheduleType, offTime, this.weekDay.value).subscribe(response => {
|
||||
this.translate.get('GC.MSG_SCHEDULE_SET').subscribe((res: string) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
this.resetSchedule(offTime);
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
this.gcRepoService.postScheduleGc(this.CronScheduleComponent.scheduleType, cron).subscribe(
|
||||
response => {
|
||||
this.translate.get("GC.MSG_SCHEDULE_SET").subscribe((res) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
this.getJobs();
|
||||
},
|
||||
error => {
|
||||
this.errorHandler.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,6 @@
|
||||
export const WEEKDAYS = [
|
||||
{value: 0, text: "WEEKLY.MONDAY"},
|
||||
{value: 1, text: "WEEKLY.TUESDAY"},
|
||||
{value: 2, text: "WEEKLY.WEDNESDAY"},
|
||||
{value: 3, text: "WEEKLY.THURSDAY"},
|
||||
{value: 4, text: "WEEKLY.FRIDAY"},
|
||||
{value: 5, text: "WEEKLY.SATURDAY"},
|
||||
{value: 6, text: "WEEKLY.SUNDAY"}
|
||||
];
|
||||
|
||||
export const SCHEDULE_TYPE = {
|
||||
NONE: "None",
|
||||
DAILY: "Daily",
|
||||
WEEKLY: "Weekly"
|
||||
};
|
||||
|
||||
export const SCHEDULE_TYPE_NONE = "None";
|
||||
|
||||
export const ONE_MINITUE = 60000;
|
||||
export const THREE_SECONDS = 3000;
|
||||
|
@ -36,29 +36,25 @@ export class GcRepoService {
|
||||
return this.gcApiRepository.getSchedule();
|
||||
}
|
||||
|
||||
public postScheduleGc(type, offTime, weekday ?): Observable <any> {
|
||||
public postScheduleGc(type, cron): Observable <any> {
|
||||
let param = {
|
||||
"schedule": {
|
||||
"type": type,
|
||||
"offtime": offTime,
|
||||
"cron": cron,
|
||||
}
|
||||
};
|
||||
if (weekday) {
|
||||
param.schedule["weekday"] = weekday;
|
||||
}
|
||||
|
||||
return this.gcApiRepository.postSchedule(param);
|
||||
}
|
||||
|
||||
public putScheduleGc(type, offTime, weekday ?): Observable <any> {
|
||||
public putScheduleGc(type, cron): Observable <any> {
|
||||
let param = {
|
||||
"schedule": {
|
||||
"type": type,
|
||||
"offtime": offTime,
|
||||
"cron": cron,
|
||||
}
|
||||
};
|
||||
if (weekday) {
|
||||
param.schedule["weekday"] = weekday;
|
||||
}
|
||||
|
||||
return this.gcApiRepository.putSchedule(param);
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
const ONE_HOUR_SECONDS: number = 3600;
|
||||
const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
|
||||
|
||||
@Injectable()
|
||||
export class GcUtility {
|
||||
private _localTime: Date = new Date();
|
||||
public getOffTime(v: string) {
|
||||
let values: string[] = v.split(":");
|
||||
if (!values || values.length !== 2) {
|
||||
return;
|
||||
}
|
||||
let hours: number = +values[0];
|
||||
let minutes: number = +values[1];
|
||||
// Convert to UTC time
|
||||
let timezoneOffset: number = this._localTime.getTimezoneOffset();
|
||||
let utcTimes: number = hours * ONE_HOUR_SECONDS + minutes * 60;
|
||||
utcTimes += timezoneOffset * 60;
|
||||
if (utcTimes < 0) {
|
||||
utcTimes += ONE_DAY_SECONDS;
|
||||
}
|
||||
if (utcTimes >= ONE_DAY_SECONDS) {
|
||||
utcTimes -= ONE_DAY_SECONDS;
|
||||
}
|
||||
return utcTimes;
|
||||
}
|
||||
|
||||
public getDailyTime(v: number ) {
|
||||
let timeOffset: number = 0; // seconds
|
||||
timeOffset = + v;
|
||||
// Convert to current time
|
||||
let timezoneOffset: number = this._localTime.getTimezoneOffset();
|
||||
// Local time
|
||||
timeOffset = timeOffset - timezoneOffset * 60;
|
||||
if (timeOffset < 0) {
|
||||
timeOffset = timeOffset + ONE_DAY_SECONDS;
|
||||
}
|
||||
|
||||
if (timeOffset >= ONE_DAY_SECONDS) {
|
||||
timeOffset -= ONE_DAY_SECONDS;
|
||||
}
|
||||
|
||||
// To time string
|
||||
let hours: number = Math.floor(timeOffset / ONE_HOUR_SECONDS);
|
||||
let minutes: number = Math.floor((timeOffset - hours * ONE_HOUR_SECONDS) / 60);
|
||||
|
||||
let timeStr: string = "" + hours;
|
||||
if (hours < 10) {
|
||||
timeStr = "0" + timeStr;
|
||||
}
|
||||
if (minutes < 10) {
|
||||
timeStr += ":0";
|
||||
} else {
|
||||
timeStr += ":";
|
||||
}
|
||||
timeStr += minutes;
|
||||
|
||||
return timeStr;
|
||||
}
|
||||
}
|
@ -12,8 +12,7 @@ export class GcJobData {
|
||||
|
||||
export class Schedule {
|
||||
type: string;
|
||||
weekday: number;
|
||||
offtime: number;
|
||||
cron: string;
|
||||
}
|
||||
export class GcJobViewModel {
|
||||
id: number;
|
||||
@ -24,14 +23,4 @@ export class GcJobViewModel {
|
||||
details: string;
|
||||
}
|
||||
|
||||
export class WeekDay {
|
||||
value: number;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export class GcScheduleViewModel {
|
||||
type: string;
|
||||
weekDay: string;
|
||||
dailyTime: string;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,5 @@ export * from "./gc.component";
|
||||
export * from "./gc.const";
|
||||
export * from "./gc.api.repository";
|
||||
export * from "./gc.service";
|
||||
export * from "./gc.utility";
|
||||
export * from "./gc.viewmodel.factory";
|
||||
export * from "./gcLog";
|
||||
|
@ -9,6 +9,7 @@ import { VulnerabilityConfigComponent } from './vulnerability/vulnerability-conf
|
||||
import { RegistryConfigComponent } from './registry-config.component';
|
||||
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
|
||||
import { GcComponent } from './gc/gc.component';
|
||||
import { CronScheduleComponent } from '../cron-schedule/cron-schedule.component';
|
||||
|
||||
import {
|
||||
ConfigurationService,
|
||||
@ -64,7 +65,8 @@ describe('RegistryConfigComponent (inline template)', () => {
|
||||
VulnerabilityConfigComponent,
|
||||
RegistryConfigComponent,
|
||||
ConfirmationDialogComponent,
|
||||
GcComponent
|
||||
GcComponent,
|
||||
CronScheduleComponent
|
||||
],
|
||||
providers: [
|
||||
ErrorHandler,
|
||||
|
@ -0,0 +1,50 @@
|
||||
<div class="normal-wrapper flex-layout" *ngIf="!isEditMode">
|
||||
<span class="font-style">{{ labelCurrent | translate }}</span>
|
||||
<span>{{(originScheduleType ? 'SCHEDULE.'+ originScheduleType.toUpperCase(): "") | translate}}</span>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.HOURLY" href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.HOURLY_CRON' | translate}}</span>
|
||||
</a>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.WEEKLY" href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.WEEKLY_CRON' | translate}}</span>
|
||||
</a>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.DAILY" href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.DAILY_CRON' | translate}}</span>
|
||||
</a>
|
||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ "SCHEDULE.CRON" | translate }} :</span>
|
||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ oriCron }}</span>
|
||||
<button class="btn btn-outline btn-sm" (click)="editSchedule()">
|
||||
{{ "BUTTON.EDIT" | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="setting-wrapper flex-layout" *ngIf="isEditMode">
|
||||
<span class="font-style">{{ labelEdit | translate }}</span>
|
||||
<div class="select select-schedule">
|
||||
<select name="gcPolicy" [(ngModel)]="scheduleType">
|
||||
<option [value]="SCHEDULE_TYPE.NONE">{{'SCHEDULE.NONE' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.HOURLY">{{'SCHEDULE.HOURLY' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.DAILY">{{'SCHEDULE.DAILY' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.WEEKLY">{{'SCHEDULE.WEEKLY' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.CUSTOM">{{'SCHEDULE.CUSTOM' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<span [hidden]="scheduleType!==SCHEDULE_TYPE.CUSTOM">{{ "SCHEDULE.CRON" | translate }} :</span>
|
||||
<div [hidden]="scheduleType!==SCHEDULE_TYPE.CUSTOM" >
|
||||
<label for="targetCron" aria-haspopup="true" role="tooltip" [class.invalid]="cronStringInput.invalid && (cronStringInput.dirty || cronStringInput.touched)" class="tooltip tooltip-validation tooltip-md tooltip-top-right">
|
||||
<input type="text" name=targetCron id="targetCron" #cronStringInput="ngModel" required class="form-control cron-input"
|
||||
[(ngModel)]="cronString">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.CRON_REQUIRED' | translate }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm"
|
||||
(click)="save()">
|
||||
{{ "BUTTON.SAVE" | translate }}
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm" (click)="isEditMode= false">
|
||||
{{ "BUTTON.CANCEL" | translate }}
|
||||
</button>
|
||||
</div>
|
@ -0,0 +1,45 @@
|
||||
.flex-layout {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 20px 0;
|
||||
font-size: .541667rem;
|
||||
}
|
||||
|
||||
.normal-wrapper {
|
||||
> span:first-child {
|
||||
width: 228px;
|
||||
}
|
||||
|
||||
> span:not(:first-child) {
|
||||
margin-right: 18px;
|
||||
}
|
||||
> a {
|
||||
margin-left: -10px;
|
||||
}
|
||||
button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.setting-wrapper {
|
||||
> span:first-child {
|
||||
width: 228px;
|
||||
}
|
||||
|
||||
*:not(:first-child) {
|
||||
margin-right: 18px;
|
||||
}
|
||||
|
||||
.select-schedule {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.cron-input {
|
||||
width: 195px;
|
||||
}
|
||||
}
|
||||
.font-style {
|
||||
color: #000;
|
||||
font-size: .541667rem;
|
||||
}
|
78
src/portal/lib/src/cron-schedule/cron-schedule.component.ts
Normal file
78
src/portal/lib/src/cron-schedule/cron-schedule.component.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Output,
|
||||
Input,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
SimpleChange
|
||||
} from "@angular/core";
|
||||
import { OriginCron } from "../service/interface";
|
||||
const SCHEDULE_TYPE = {
|
||||
NONE: "None",
|
||||
DAILY: "Daily",
|
||||
WEEKLY: "Weekly",
|
||||
HOURLY: "Hourly",
|
||||
CUSTOM: "Custom"
|
||||
};
|
||||
@Component({
|
||||
selector: "cron-selection",
|
||||
templateUrl: "./cron-schedule.component.html",
|
||||
styleUrls: ["./cron-schedule.component.scss"]
|
||||
})
|
||||
export class CronScheduleComponent implements OnChanges {
|
||||
@Input() originCron: OriginCron;
|
||||
@Input() labelEdit: string;
|
||||
@Input() labelCurrent: string;
|
||||
originScheduleType: string;
|
||||
oriCron: string;
|
||||
cronString: string;
|
||||
isEditMode: boolean = false;
|
||||
SCHEDULE_TYPE = SCHEDULE_TYPE;
|
||||
scheduleType: string;
|
||||
@Output() inputvalue = new EventEmitter<string>();
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
let cronChange: SimpleChange = changes["originCron"];
|
||||
if (cronChange.currentValue) {
|
||||
this.originScheduleType = cronChange.currentValue.type;
|
||||
this.oriCron = cronChange.currentValue.cron;
|
||||
}
|
||||
}
|
||||
editSchedule() {
|
||||
if (!this.originScheduleType) {
|
||||
return;
|
||||
}
|
||||
this.isEditMode = true;
|
||||
this.scheduleType = this.originScheduleType;
|
||||
if (this.scheduleType && this.scheduleType === SCHEDULE_TYPE.CUSTOM) {
|
||||
this.cronString = this.oriCron;
|
||||
} else {
|
||||
this.cronString = "";
|
||||
}
|
||||
}
|
||||
|
||||
public resetSchedule() {
|
||||
this.originScheduleType = this.scheduleType;
|
||||
this.oriCron = this.cronString;
|
||||
this.isEditMode = false;
|
||||
}
|
||||
|
||||
save(): void {
|
||||
let scheduleTerm: string = "";
|
||||
this.resetSchedule();
|
||||
if (this.scheduleType && this.scheduleType === SCHEDULE_TYPE.NONE) {
|
||||
scheduleTerm = "";
|
||||
} else if (this.scheduleType && this.scheduleType === SCHEDULE_TYPE.HOURLY) {
|
||||
scheduleTerm = "0 0 * * * *";
|
||||
} else if (this.scheduleType && this.scheduleType === SCHEDULE_TYPE.DAILY) {
|
||||
scheduleTerm = "0 0 0 * * *";
|
||||
} else if (this.scheduleType && this.scheduleType === SCHEDULE_TYPE.WEEKLY) {
|
||||
scheduleTerm = "0 0 0 * * 0";
|
||||
} else {
|
||||
scheduleTerm = this.cronString;
|
||||
}
|
||||
scheduleTerm = scheduleTerm.replace(/\s+/g, " ").trim();
|
||||
this.inputvalue.emit(scheduleTerm);
|
||||
}
|
||||
}
|
6
src/portal/lib/src/cron-schedule/index.ts
Normal file
6
src/portal/lib/src/cron-schedule/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Type } from "@angular/core";
|
||||
|
||||
import { CronScheduleComponent } from "./cron-schedule.component";
|
||||
export const CRON_SCHEDULE_DIRECTIVES: Type<any>[] = [
|
||||
CronScheduleComponent
|
||||
];
|
@ -29,6 +29,7 @@ import { CREATE_EDIT_LABEL_DIRECTIVES } from "./create-edit-label/index";
|
||||
import { LABEL_PIECE_DIRECTIVES } from "./label-piece/index";
|
||||
import { HELMCHART_DIRECTIVE } from "./helm-chart/index";
|
||||
import { IMAGE_NAME_INPUT_DIRECTIVES } from "./image-name-input/index";
|
||||
import { CRON_SCHEDULE_DIRECTIVES } from "./cron-schedule/index";
|
||||
import {
|
||||
SystemInfoService,
|
||||
SystemInfoDefaultService,
|
||||
@ -60,7 +61,6 @@ import {
|
||||
UserPermissionDefaultService
|
||||
} from './service/index';
|
||||
import { GcRepoService } from './config/gc/gc.service';
|
||||
import { GcUtility } from './config/gc/gc.utility';
|
||||
import {GcViewModelFactory} from './config/gc/gc.viewmodel.factory';
|
||||
import {GcApiRepository, GcApiDefaultRepository} from './config/gc/gc.api.repository';
|
||||
import {
|
||||
@ -210,7 +210,8 @@ export function initConfig(translateInitializer: TranslateServiceInitializer, co
|
||||
REPOSITORY_GRIDVIEW_DIRECTIVES,
|
||||
OPERATION_DIRECTIVES,
|
||||
HELMCHART_DIRECTIVE,
|
||||
IMAGE_NAME_INPUT_DIRECTIVES
|
||||
IMAGE_NAME_INPUT_DIRECTIVES,
|
||||
CRON_SCHEDULE_DIRECTIVES
|
||||
],
|
||||
exports: [
|
||||
LOG_DIRECTIVES,
|
||||
@ -237,7 +238,8 @@ export function initConfig(translateInitializer: TranslateServiceInitializer, co
|
||||
REPOSITORY_GRIDVIEW_DIRECTIVES,
|
||||
OPERATION_DIRECTIVES,
|
||||
HELMCHART_DIRECTIVE,
|
||||
IMAGE_NAME_INPUT_DIRECTIVES
|
||||
IMAGE_NAME_INPUT_DIRECTIVES,
|
||||
CRON_SCHEDULE_DIRECTIVES
|
||||
],
|
||||
providers: []
|
||||
})
|
||||
@ -275,8 +277,7 @@ export class HarborLibraryModule {
|
||||
ChannelService,
|
||||
OperationService,
|
||||
GcRepoService,
|
||||
GcViewModelFactory,
|
||||
GcUtility
|
||||
GcViewModelFactory
|
||||
]
|
||||
};
|
||||
}
|
||||
@ -305,8 +306,7 @@ export class HarborLibraryModule {
|
||||
ChannelService,
|
||||
OperationService,
|
||||
GcRepoService,
|
||||
GcViewModelFactory,
|
||||
GcUtility
|
||||
GcViewModelFactory
|
||||
]
|
||||
};
|
||||
}
|
||||
|
@ -446,3 +446,8 @@ export interface UserPrivilegeServeItem {
|
||||
action: string;
|
||||
}
|
||||
|
||||
export class OriginCron {
|
||||
type: string;
|
||||
cron: string;
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@
|
||||
"ITEM_REQUIRED": "Field is required.",
|
||||
"NUMBER_REQUIRED": "Field is required and should be numbers.",
|
||||
"PORT_REQUIRED": "Field is required and should be valid port number.",
|
||||
"CRON_REQUIRED": "Field is required and should be in cron format.",
|
||||
"EMAIL_EXISTING": "Email address already exists.",
|
||||
"USER_EXISTING": "Username is already in use.",
|
||||
"RULE_USER_EXISTING": "Name is already in use.",
|
||||
@ -642,7 +643,10 @@
|
||||
"SCANNING_POLICY": "Set image scanning policy based on different requirements. 'None': No active policy; 'Daily At': Triggering scanning at the specified time everyday.",
|
||||
"VERIFY_CERT": "Verify Cert from LDAP Server",
|
||||
"READONLY_TOOLTIP": "In read-only mode, you can not delete repositories or tags or push images. ",
|
||||
"REPO_TOOLTIP": "Users can not do any operations to the images in this mode."
|
||||
"REPO_TOOLTIP": "Users can not do any operations to the images in this mode.",
|
||||
"HOURLY_CRON":"Run once an hour, beginning of hour",
|
||||
"WEEKLY_CRON":"Run once a week, midnight between Sat/Sun",
|
||||
"DAILY_CRON":"Run once a day, midnight"
|
||||
},
|
||||
"LDAP": {
|
||||
"URL": "LDAP URL",
|
||||
@ -876,7 +880,10 @@
|
||||
"NONE": "None",
|
||||
"DAILY": "Daily",
|
||||
"WEEKLY": "Weekly",
|
||||
"HOURLY": "Hourly",
|
||||
"CUSTOM": "Custom",
|
||||
"MANUAL": "Manual",
|
||||
"CRON": "cron",
|
||||
"ON": "on",
|
||||
"AT": "at"
|
||||
},
|
||||
|
@ -65,6 +65,7 @@
|
||||
"ITEM_REQUIRED": "Campo obligatorio.",
|
||||
"NUMBER_REQUIRED": "El campo es obligatorio y debería ser un número.",
|
||||
"PORT_REQUIRED": "El campo es obligatorio y debería ser un número de puerto válido.",
|
||||
"CRON_REQUIRED": "El campo es obligatorio y debe estar en formato cron.",
|
||||
"EMAIL_EXISTING": "Esa dirección de email ya existe.",
|
||||
"USER_EXISTING": "Ese nombre de usuario ya existe.",
|
||||
"RULE_USER_EXISTING": "Name is already in use.",
|
||||
@ -641,7 +642,10 @@
|
||||
"SCANNING_POLICY": "Set image scanning policy based on different requirements. 'None': No active policy; 'Daily At': Triggering scanning at the specified time everyday.",
|
||||
"VERIFY_CERT": "Verify Cert from LDAP Server",
|
||||
"READONLY_TOOLTIP": "In read-only mode, you can not delete repositories or tags or push images. ",
|
||||
"GC_POLICY": ""
|
||||
"GC_POLICY": "",
|
||||
"HOURLY_CRON":"Run once an hour, beginning of hour",
|
||||
"WEEKLY_CRON":"Run once a week, midnight between Sat/Sun",
|
||||
"DAILY_CRON":"Run once a day, midnight"
|
||||
|
||||
},
|
||||
"LDAP": {
|
||||
|
@ -54,6 +54,7 @@
|
||||
"ITEM_REQUIRED": "Le champ est obligatoire.",
|
||||
"NUMBER_REQUIRED": "Le champ est obligatoire et doit être numérique.",
|
||||
"PORT_REQUIRED": "Le champ est obligatoire et doit être un numéro de port valide.",
|
||||
"CRON_REQUIRED": "Le champ est obligatoire et doit être au format cron.",
|
||||
"EMAIL_EXISTING": "L'adresse e-mail existe déjà.",
|
||||
"USER_EXISTING": "Le nom d'utilisateur est déjà utilisé.",
|
||||
"NONEMPTY": "Can't be empty",
|
||||
@ -613,7 +614,10 @@
|
||||
"ROOT_CERT_DOWNLOAD": "Téléchargez le certificat racine du dépôt.",
|
||||
"SCANNING_POLICY": "Définissez la politique d'analyse des images en fonction des différentes exigences. 'Aucune' : pas de politique active; 'Tousles jours à' : déclenchement du balayage à l'heure spécifiée tous les jours.",
|
||||
"READONLY_TOOLTIP": "In read-only mode, you can not delete repositories or tags or push images. ",
|
||||
"GC_POLICY": ""
|
||||
"GC_POLICY": "",
|
||||
"HOURLY_CRON":"Run once an hour, beginning of hour",
|
||||
"WEEKLY_CRON":"Run once a week, midnight between Sat/Sun",
|
||||
"DAILY_CRON":"Run once a day, midnight"
|
||||
},
|
||||
"LDAP": {
|
||||
"URL": "URL LDAP",
|
||||
|
@ -65,6 +65,7 @@
|
||||
"ITEM_REQUIRED": "Campo é obrigatório.",
|
||||
"NUMBER_REQUIRED": "Campo é obrigatório e deve ser numerico.",
|
||||
"PORT_REQUIRED": "Campo é obrigatório e deve ser um número de porta válido.",
|
||||
"CRON_REQUIRED": "O campo é obrigatório e deve estar no formato cron.",
|
||||
"EMAIL_EXISTING": "Email já existe.",
|
||||
"USER_EXISTING": "Nome de usuário já está em uso.",
|
||||
"RULE_USER_EXISTING": "Nome já em uso.",
|
||||
@ -635,7 +636,10 @@
|
||||
"SCANNING_POLICY": "Configura a política de análise das imagens baseado em diferentes requisitos. 'Nenhum': Nenhuma política ativa; 'Diariamente em': Dispara a análise diariamente no horário especificado.",
|
||||
"VERIFY_CERT": "Verificar o Certificado do Servidor LDAP",
|
||||
"READONLY_TOOLTIP": "Em modo somente leitura, você não pode remover repositórios ou tags ou enviar imagens. ",
|
||||
"REPO_TOOLTIP": "Usuários não podem efetuar qualquer operação nas imagens nesse modo."
|
||||
"REPO_TOOLTIP": "Usuários não podem efetuar qualquer operação nas imagens nesse modo.",
|
||||
"HOURLY_CRON":"Run once an hour, beginning of hour",
|
||||
"WEEKLY_CRON":"Run once a week, midnight between Sat/Sun",
|
||||
"DAILY_CRON":"Run once a day, midnight"
|
||||
},
|
||||
"LDAP": {
|
||||
"URL": "URL LDAP",
|
||||
|
@ -65,6 +65,7 @@
|
||||
"ITEM_REQUIRED": "此项为必填项。",
|
||||
"NUMBER_REQUIRED": "此项为必填项且为数字。",
|
||||
"PORT_REQUIRED": "此项为必填项且为合法端口号。",
|
||||
"CRON_REQUIRED": "此项为必填项且为cron格式。",
|
||||
"EMAIL_EXISTING": "邮件地址已经存在。",
|
||||
"USER_EXISTING": "用户名已经存在。",
|
||||
"RULE_USER_EXISTING": "名称已经存在。",
|
||||
@ -641,7 +642,10 @@
|
||||
"SCANNING_POLICY": "基于不同需求设置镜像扫描策略。‘无’:不设置任何策略;‘每日定时’:每天在设置的时间定时执行扫描。",
|
||||
"VERIFY_CERT": "检查来自LDAP服务端的证书",
|
||||
"READONLY_TOOLTIP": "选中,表示正在维护状态,不可删除仓库及标签,也不可以推送镜像。",
|
||||
"REPO_TOOLTIP": "用户在此模式下无法对图像执行任何操作。"
|
||||
"REPO_TOOLTIP": "用户在此模式下无法对图像执行任何操作。",
|
||||
"HOURLY_CRON":"每小时运行一次",
|
||||
"WEEKLY_CRON":"每周一次,周六/周日午夜之间开始",
|
||||
"DAILY_CRON":"每天午夜运行一次"
|
||||
},
|
||||
"LDAP": {
|
||||
"URL": "LDAP URL",
|
||||
|
Loading…
Reference in New Issue
Block a user