Merge pull request #7083 from pureshine/support-cron

Refactoring gc ui support cron
This commit is contained in:
Fangyuan Cheng 2019-03-07 16:52:44 +08:00 committed by GitHub
commit 41f443d3e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 321 additions and 238 deletions

View File

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

View File

@ -10,6 +10,10 @@
font-size: .541667rem;
}
.cron-selection {
margin-top: 20px;
}
.setting-wrapper {
label {
width: 228px;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -0,0 +1,6 @@
import { Type } from "@angular/core";
import { CronScheduleComponent } from "./cron-schedule.component";
export const CRON_SCHEDULE_DIRECTIVES: Type<any>[] = [
CronScheduleComponent
];

View File

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

View File

@ -446,3 +446,8 @@ export interface UserPrivilegeServeItem {
action: string;
}
export class OriginCron {
type: string;
cron: string;
}

View File

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

View File

@ -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": {

View File

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

View File

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

View File

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