Modify cron regex for UI (#14254)

Signed-off-by: sshijun <sshijun@vmware.com>
This commit is contained in:
Will Sun 2021-02-18 15:09:10 +08:00 committed by GitHub
parent 202342cf0c
commit 74b6bfe731
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 36 deletions

View File

@ -1,6 +1,6 @@
{
"name": "harbor",
"version": "2.2.0",
"version": "2.3.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -5391,6 +5391,11 @@
"object-assign": "^4.1.1"
}
},
"cron-validator": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.2.1.tgz",
"integrity": "sha512-RqdpGSokGFICPc8qAkT38aXqZLLanXghQTK2q7a2x2FabSwDd2ARrazd5ElEWAXzToUcMG4cZIwDH+5RM0q1mA=="
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",

View File

@ -46,6 +46,7 @@
"@webcomponents/webcomponentsjs": "^2.0.0",
"buffer": "^5.2.1",
"core-js": "^2.5.4",
"cron-validator": "^1.2.1",
"intl": "^1.2.5",
"jasmine-core": "^3.3.0",
"mutationobserver-shim": "^0.3.2",

View File

@ -176,15 +176,16 @@
</select>
</div>
<div formGroupName="trigger_settings" class="clr-form-control">
<div [hidden]="isNotSchedule()">
<label class="required">Cron String</label>
<label for="targetCron" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-sm tooltip-top-right"
[class.invalid]="!isNotSchedule() && cronTouched && !cronInputValid(ruleForm.value.trigger?.trigger_settings?.cron || '')">
<input (input)="inputInvalid($event)" type="text" name=targetCron id="targetCron" required class="form-control cron-input clr-input" formControlName="cron">
<span class="tooltip-content">
<div class="flex" [hidden]="isNotSchedule()">
<label for="targetCron" class="required">Cron String</label>
<div class="clr-control-container" [class.clr-error]="cronInputShouldShowError()">
<div class="clr-input-wrapper">
<input autocomplete="off" (input)="inputInvalid($event)" type="text" name=targetCron id="targetCron" required class="form-control cron-input clr-input" formControlName="cron">
</div>
<clr-control-error *ngIf="cronInputShouldShowError()">
{{'TOOLTIP.CRON_REQUIRED' | translate }}
</span>
</label>
</clr-control-error>
</div>
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-lg tooltip-top-left top-7 cron-tooltip">
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
<div class="tooltip-content table-box">

View File

@ -283,4 +283,6 @@ clr-modal {
.select-width {
min-width:11rem;
}
.flex {
display: flex;
}

View File

@ -183,7 +183,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
!this.isRuleNameValid ||
(!this.isPushMode && !sourceRegistry ||
this.isPushMode && !destRegistry)
|| !(!this.isNotSchedule() && cron && this.cronInputValid(this.ruleForm.value.trigger.trigger_settings.cron || '')
|| !(!this.isNotSchedule() && cron && cronRegex(this.ruleForm.value.trigger.trigger_settings.cron || '')
|| this.isNotSchedule()));
}
@ -545,19 +545,13 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
}
return filtersArray;
}
cronInputValid(cronValue): boolean {
return cronRegex(cronValue);
}
get cronTouched(): boolean {
let triggerControl = this.ruleForm.controls.trigger as FormGroup;
if (!triggerControl) {
return false;
}
let trigger_settingsControls = triggerControl.controls.trigger_settings as FormGroup;
if (!trigger_settingsControls) {
return false;
}
return trigger_settingsControls.controls.cron.touched || trigger_settingsControls.controls.cron.dirty;
cronInputShouldShowError(): boolean {
return this.ruleForm && this.ruleForm.get('trigger')
&& this.ruleForm.get('trigger').get('trigger_settings')
&& this.ruleForm.get('trigger').get('trigger_settings').get('cron')
&& (this.ruleForm.get('trigger').get('trigger_settings').get('cron').touched
|| this.ruleForm.get('trigger').get('trigger_settings').get('cron').dirty)
&& !cronRegex(this.ruleForm.get('trigger').get('trigger_settings').get('cron').value);
}
stickLabel(value, index) {
value.select = !value.select;
@ -582,6 +576,10 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
if (!e.target.value || (e.target.value && e.target.value.indexOf(PREFIX)) !== 0) {
e.target.value = PREFIX;
}
e.target.value = e.target.value.replace(/\s+/g, ' ');
if (e.target.value && e.target.value.split(/\s+/g).length > 6) {
e.target.value = e.target.value.trim();
}
}
}
}

View File

@ -40,7 +40,7 @@
<div class="height-1rem clr-input-wrapper">
<label for="targetCron" aria-haspopup="true" role="tooltip" [class.clr-error]="dateInvalid"
class="tooltip tooltip-validation tooltip-md tooltip-top-left cron-label">
<input type="text" (blur)="blurInvalid()" (input)="inputInvalid($event)" name="targetCron" id="targetCron"
<input autocomplete="off" type="text" (blur)="blurInvalid()" (input)="inputInvalid($event)" name="targetCron" id="targetCron"
#cronStringInput="ngModel" required class="clr-input form-control ml-1" [(ngModel)]="cronString">
<clr-tooltip>
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>

View File

@ -3,8 +3,9 @@ import { HttpHeaders } from '@angular/common/http';
import { RequestQueryParams } from '../services';
import { DebugElement } from '@angular/core';
import { Comparator, State, HttpOptionInterface, HttpOptionTextInterface, QuotaUnitInterface } from '../services';
import { QuotaUnits, StorageMultipleConstant, LimitCount } from '../entities/shared.const';
import { QuotaUnits, StorageMultipleConstant } from '../entities/shared.const';
import { AbstractControl } from "@angular/forms";
import { isValidCron } from 'cron-validator';
/**
* Api levels
*/
@ -463,17 +464,16 @@ export function getChanges(original: any, afterChange: any): { [key: string]: an
return changes;
}
/**
* validate cron expressions
* @param testValue
*/
export function cronRegex(testValue: any): boolean {
const regSecond = "^((([0-9])*|(\\*))(\\-|\\,|\\/)?([0-9])*)*\\s+";
const regMinute = "((([0-9])*|(\\*))(\\-|\\,|\\/)?([0-9])*)*\\s+";
const regHour = "((([0-9])*|(\\*))(\\-|\\,|\\/)?([0-9])*)*\\s+";
const regDay = "((([0-9])*|(\\*|\\?))(\\-|\\,|\\/)?([0-9])*)*\\s+";
const regMonth = "((([0-9a-zA-Z])*|(\\*))(\\-|\\,|\\/)?([0-9a-zA-Z])*)*\\s+";
const regWeek = "(((([0-9a-zA-Z])*|(\\*|\\?))(\\-|\\,|\\/)?([0-9a-zA-Z])*))*(|\\s)+";
const regYear = "((([0-9])*|(\\*|\\?))(\\-|\\,|\\/)?([0-9])*)$";
const regEx = regSecond + regMinute + regHour + regDay + regMonth + regWeek + regYear;
let reg = new RegExp(regEx, "i");
return reg.test(testValue.trim());
// must have 6 fields
if (testValue && testValue.trim().split(/\s+/g).length < 6) {
return false;
}
return isValidCron(testValue, {seconds: true, alias: true, allowBlankDay: true});
}
/**