Fix issues about confirm buttons and date validation.

This commit is contained in:
kunw 2017-04-25 20:34:28 +08:00
parent 35489e40ff
commit adee392c3c
24 changed files with 195 additions and 62 deletions

View File

@ -22,8 +22,20 @@
</div>
</clr-dropdown>
<div class="flex-xs-middle">
<clr-icon shape="date"></clr-icon><input type="date" #fromTime (change)="doSearchByTimeRange(fromTime.value, 'begin')">
<clr-icon shape="date"></clr-icon><input type="date" #toTime (change)="doSearchByTimeRange(toTime.value, 'end')">
<clr-icon shape="date"></clr-icon>
<label for="fromDateInput" aria-haspopup="true" role="tooltip" [class.invalid]="fromTime.errors && fromTime.errors.dateValidator && (fromTime.dirty || fromTime.touched)" [class.valid]="fromTime.valid" class="tooltip tooltip-validation invalid tooltip-sm">
<input id="fromDateInput" type="date" #fromTime="ngModel" name="from" [(ngModel)]="queryParam.fromTime" dateValidator placeholder="dd/mm/yyyy" (change)="doSearchByStartTime(!(fromTime.errors && fromTime.errors.dateValidator), fromTime.value)">
<span *ngIf="fromTime.errors && fromTime.errors.dateValidator && (fromTime.dirty || fromTime.touched)" class="tooltip-content">
{{'AUDIT_LOG.INVALID_DATE' | translate }}
</span>
</label>
<clr-icon shape="date"></clr-icon>
<label for="toDateInput" aria-haspopup="true" role="tooltip" [class.invalid]="toTime.errors && toTime.errors.dateValidator && (toTime.dirty || toTime.touched)" [class.valid]="toTime.valid" class="tooltip tooltip-validation invalid tooltip-sm">
<input id="toDateInput" type="date" #toTime="ngModel" name="to" [(ngModel)]="queryParam.toTime" dateValidator placeholder="dd/mm/yyyy" (change)="doSearchByEndTime(!(toTime.errors && toTime.errors.dateValidator),toTime.value)">
<span *ngIf="toTime.errors && toTime.errors.dateValidator && (toTime.dirty || toTime.touched)" class="tooltip-content">
{{'AUDIT_LOG.INVALID_DATE' | translate }}
</span>
</label>
</div>
</div>
</div>

View File

@ -105,15 +105,29 @@ export class AuditLogComponent implements OnInit {
this.retrieve();
}
doSearchByTimeRange(strDate: string, target: string): void {
let oneDayOffset = 3600 * 24;
switch(target) {
case 'begin':
convertDate(strDate: string): string {
if(/^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$/.test(strDate)) {
let parts = strDate.split(/[-\/]/);
strDate = parts[2] /*Year*/ + '-' +parts[1] /*Month*/ + '-' + parts[0] /*Date*/;
}
return strDate;
}
doSearchByStartTime(valid: boolean, strDate: string): void {
this.queryParam.begin_timestamp = 0;
if(valid && strDate){
strDate = this.convertDate(strDate);
this.queryParam.begin_timestamp = new Date(strDate).getTime() / 1000;
break;
case 'end':
}
this.retrieve();
}
doSearchByEndTime(valid: boolean, strDate: string): void {
this.queryParam.end_timestamp = 0;
if(valid && strDate) {
strDate = this.convertDate(strDate);
let oneDayOffset = 3600 * 24;
this.queryParam.end_timestamp = new Date(strDate).getTime() / 1000 + oneDayOffset;
break;
}
this.retrieve();
}

View File

@ -21,7 +21,8 @@ import { RecentLogComponent } from './recent-log.component';
imports: [SharedModule],
declarations: [
AuditLogComponent,
RecentLogComponent],
RecentLogComponent
],
providers: [AuditLogService],
exports: [
AuditLogComponent,

View File

@ -20,7 +20,7 @@
</label>
</div>
<div class="form-group" style="padding-left: 135px;">
<label class="col-md-3 form-group-label-override">{{'PROJECT.PUBLIC_OR_PRIVATE' | translate}}</label>
<label class="col-md-3 form-group-label-override">{{'PROJECT.ACCESS_LEVEL' | translate}}</label>
<div class="checkbox-inline">
<input type="checkbox" id="create_project_public" [(ngModel)]="project.public" name="public">
<label for="create_project_public"></label>

View File

@ -1,6 +1,6 @@
<clr-datagrid (clrDgRefresh)="refresh($event)">
<clr-dg-column>{{'PROJECT.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.PUBLIC_OR_PRIVATE' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.ACCESS_LEVEL' | translate}}</clr-dg-column>
<clr-dg-column *ngIf="showRoleInfo">{{'PROJECT.ROLE' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column>

View File

@ -22,7 +22,7 @@ import { MemberService } from './member.service';
import { AddMemberComponent } from './add-member/add-member.component';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
import { ConfirmationTargets, ConfirmationState } from '../../shared/shared.const';
import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../../shared/shared.const';
import { ConfirmationDialogService } from '../../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message';
@ -149,7 +149,8 @@ export class MemberComponent implements OnInit, OnDestroy {
'MEMBER.DELETION_SUMMARY',
m.username,
m.user_id,
ConfirmationTargets.PROJECT_MEMBER
ConfirmationTargets.PROJECT_MEMBER,
ConfirmationButtons.DELETE_CANCEL
);
this.deletionDialogService.openComfirmDialog(deletionMessage);
}

View File

@ -29,7 +29,7 @@ import { Response } from '@angular/http';
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../shared/confirmation-dialog/confirmation-message';
import { ConfirmationTargets, ConfirmationState } from '../shared/shared.const';
import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../shared/shared.const';
import { Subscription } from 'rxjs/Subscription';
@ -178,7 +178,8 @@ export class ProjectComponent implements OnInit, OnDestroy {
'PROJECT.DELETION_SUMMARY',
p.name,
p.project_id,
ConfirmationTargets.PROJECT
ConfirmationTargets.PROJECT,
ConfirmationButtons.DELETE_CANCEL
);
this.deletionDialogService.openComfirmDialog(deletionMessage);
}

View File

@ -19,7 +19,7 @@ import { MessageHandlerService } from '../../shared/message-handler/message-hand
import { ConfirmationDialogService } from '../../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message';
import { ConfirmationTargets, ConfirmationState } from '../../shared/shared.const';
import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../../shared/shared.const';
import { Subscription } from 'rxjs/Subscription';
@ -149,7 +149,8 @@ export class DestinationComponent implements OnInit {
'REPLICATION.DELETION_SUMMARY_TARGET',
target.name,
target.id,
ConfirmationTargets.TARGET);
ConfirmationTargets.TARGET,
ConfirmationButtons.DELETE_CANCEL);
this.deletionDialogService.openComfirmDialog(deletionMessage);
}
}

View File

@ -39,8 +39,20 @@
</select>
</div>
<div class="flex-items-xs-middle">
<clr-icon shape="date"></clr-icon><input type="date" #fromTime (change)="doJobSearchByStartTime(fromTime.value)">
<clr-icon shape="date"></clr-icon><input type="date" #toTime (change)="doJobSearchByEndTime(toTime.value)">
<clr-icon shape="date"></clr-icon>
<label for="fromDateInput" aria-haspopup="true" role="tooltip" [class.invalid]="fromTime.errors && fromTime.errors.dateValidator && (fromTime.dirty || fromTime.touched)" [class.valid]="fromTime.valid" class="tooltip tooltip-validation invalid tooltip-sm">
<input id="fromDateInput" type="date" #fromTime="ngModel" name="from" [(ngModel)]="currentJobSearchOption.fromTime" dateValidator placeholder="dd/mm/yyyy" (change)="doJobSearchByStartTime(!(fromTime.errors && fromTime.errors.dateValidator), fromTime.value)">
<span *ngIf="fromTime.errors && fromTime.errors.dateValidator && (fromTime.dirty || fromTime.touched)" class="tooltip-content">
{{'AUDIT_LOG.INVALID_DATE' | translate }}
</span>
</label>
<clr-icon shape="date"></clr-icon>
<label for="toDateInput" aria-haspopup="true" role="tooltip" [class.invalid]="toTime.errors && toTime.errors.dateValidator && (toTime.dirty || toTime.touched)" [class.valid]="toTime.valid" class="tooltip tooltip-validation invalid tooltip-sm">
<input id="toDateInput" type="date" #toTime="ngModel" name="to" [(ngModel)]="currentJobSearchOption.toTime" dateValidator placeholder="dd/mm/yyyy" (change)="doJobSearchByEndTime(!(toTime.errors && toTime.errors.dateValidator),toTime.value)">
<span *ngIf="toTime.errors && toTime.errors.dateValidator && (toTime.dirty || toTime.touched)" class="tooltip-content">
{{'AUDIT_LOG.INVALID_DATE' | translate }}
</span>
</label>
</div>
</div>
</div>

View File

@ -232,20 +232,31 @@ export class ReplicationComponent implements OnInit {
(option === 1) ? this.currentJobSearchOption = 0 : this.currentJobSearchOption = 1;
}
doJobSearchByStartTime(strDate: string) {
if(!strDate || strDate.trim() === '') {
strDate = 0 + '';
convertDate(strDate: string): string {
if(/^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$/.test(strDate)) {
let parts = strDate.split(/[-\/]/);
strDate = parts[2] /*Year*/ + '-' +parts[1] /*Month*/ + '-' + parts[0] /*Date*/;
}
return strDate;
}
doJobSearchByStartTime(valid: boolean, strDate: string) {
this.search.startTime = '';
if(valid && strDate) {
strDate = this.convertDate(strDate);
console.log(strDate);
this.search.startTime = (new Date(strDate).getTime() / 1000) + '';
}
(strDate === '0') ? this.search.startTime = '' : this.search.startTime = (new Date(strDate).getTime() / 1000) + '';
this.fetchPolicyJobs();
}
doJobSearchByEndTime(strDate: string) {
if(!strDate || strDate.trim() === '') {
strDate = 0 + '';
doJobSearchByEndTime(valid: boolean, strDate: string) {
this.search.endTime = '';
if(valid && strDate) {
strDate = this.convertDate(strDate);
let oneDayOffset = 3600 * 24;
this.search.endTime = (new Date(strDate).getTime() / 1000 + oneDayOffset) + '';
}
let oneDayOffset = 3600 * 24;
(strDate === '0') ? this.search.endTime = '' : this.search.endTime = (new Date(strDate).getTime() / 1000 + oneDayOffset) + '';
this.fetchPolicyJobs();
}
}

View File

@ -18,7 +18,7 @@ import { RepositoryService } from './repository.service';
import { Repository } from './repository';
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
import { ConfirmationState, ConfirmationTargets } from '../shared/shared.const';
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../shared/shared.const';
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service';
@ -115,7 +115,8 @@ export class RepositoryComponent implements OnInit {
'REPOSITORY.DELETION_SUMMARY_REPO',
repoName,
repoName,
ConfirmationTargets.REPOSITORY);
ConfirmationTargets.REPOSITORY,
ConfirmationButtons.DELETE_CANCEL);
this.deletionDialogService.openComfirmDialog(message);
}

View File

@ -16,7 +16,7 @@ import { ActivatedRoute } from '@angular/router';
import { RepositoryService } from '../repository.service';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
import { ConfirmationTargets, ConfirmationState } from '../../shared/shared.const';
import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../../shared/shared.const';
import { ConfirmationDialogService } from '../../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message';
@ -155,25 +155,25 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
deleteTag(tag: TagView) {
if (tag) {
let titleKey: string, summaryKey: string, content: string, confirmOnly: boolean;
let titleKey: string, summaryKey: string, content: string, buttons: ConfirmationButtons;
if (tag.signed) {
titleKey = 'REPOSITORY.DELETION_TITLE_TAG_DENIED';
summaryKey = 'REPOSITORY.DELETION_SUMMARY_TAG_DENIED';
confirmOnly = true;
buttons = ConfirmationButtons.CLOSE;
content = 'notary -s https://' + this.registryUrl + ':4443 -d ~/.docker/trust remove -p ' + this.registryUrl + '/' + this.repoName + ' ' + tag.tag;
} else {
titleKey = 'REPOSITORY.DELETION_TITLE_TAG';
summaryKey = 'REPOSITORY.DELETION_SUMMARY_TAG';
buttons = ConfirmationButtons.DELETE_CANCEL;
content = tag.tag;
confirmOnly = false;
}
let message = new ConfirmationMessage(
titleKey,
summaryKey,
content,
tag,
ConfirmationTargets.TAG);
message.confirmOnly = confirmOnly;
ConfirmationTargets.TAG,
buttons);
this.deletionDialogService.openComfirmDialog(message);
}
}

View File

@ -6,8 +6,21 @@
</div>
<div class="confirmation-content">{{dialogContent}}</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" *ngIf="!confirmOnly" (click)="cancel()">{{'BUTTON.NO' | translate}}</button>
<button type="button" class="btn btn-primary" (click)="confirm()">{{ buttonKey | translate}}</button>
<div class="modal-footer" [ngSwitch]="buttons">
<ng-template [ngSwitchCase]="0">
<button type="button" class="btn btn-outline" (click)="cancel()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-primary" (click)="confirm()">{{ 'BUTTON.CONFIRM' | translate}}</button>
</ng-template>
<ng-template [ngSwitchCase]="1">
<button type="button" class="btn btn-outline" (click)="cancel()">{{'BUTTON.NO' | translate}}</button>
<button type="button" class="btn btn-primary" (click)="confirm()">{{ 'BUTTON.YES' | translate}}</button>
</ng-template>
<ng-template [ngSwitchCase]="2">
<button type="button" class="btn btn-outline" (click)="cancel()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-danger" (click)="confirm()">{{ 'BUTTON.DELETE' | translate}}</button>
</ng-template>
<ng-template [ngSwitchCase]="3">
<button type="button" class="btn btn-primary" (click)="cancel()">{{'BUTTON.CLOSE' | translate}}</button>
</ng-template>
</div>
</clr-modal>

View File

@ -18,7 +18,7 @@ import { TranslateService } from '@ngx-translate/core';
import { ConfirmationDialogService } from './confirmation-dialog.service';
import { ConfirmationMessage } from './confirmation-message';
import { ConfirmationAcknowledgement } from './confirmation-state-message';
import { ConfirmationState, ConfirmationTargets } from '../shared.const';
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../shared.const';
@Component({
selector: 'confiramtion-dialog',
@ -30,10 +30,9 @@ export class ConfirmationDialogComponent implements OnDestroy {
opened: boolean = false;
dialogTitle: string = "";
dialogContent: string = "";
buttonKey: string = 'BUTTON.OK';
confirmOnly: boolean = false;
message: ConfirmationMessage;
annouceSubscription: Subscription;
buttons: ConfirmationButtons;
constructor(
private confirmationService: ConfirmationDialogService,
@ -42,11 +41,10 @@ export class ConfirmationDialogComponent implements OnDestroy {
this.dialogTitle = msg.title;
this.dialogContent = msg.message;
this.message = msg;
this.confirmOnly = this.message.confirmOnly;
this.buttonKey = this.confirmOnly ? 'BUTTON.CLOSE' : 'BUTTON.OK';
this.translate.get(this.dialogTitle).subscribe((res: string) => this.dialogTitle = res);
this.translate.get(this.dialogContent, { 'param': msg.param }).subscribe((res: string) => this.dialogContent = res);
//Open dialog
this.buttons = msg.buttons;
this.open();
});
}

View File

@ -11,20 +11,21 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { ConfirmationTargets } from '../../shared/shared.const';
import { ConfirmationTargets, ConfirmationButtons } from '../../shared/shared.const';
export class ConfirmationMessage {
public constructor(title: string, message: string, param: string, data: any, targetId: ConfirmationTargets) {
public constructor(title: string, message: string, param: string, data: any, targetId: ConfirmationTargets, buttons?: ConfirmationButtons) {
this.title = title;
this.message = message;
this.data = data;
this.targetId = targetId;
this.param = param;
this.buttons = buttons ? buttons : ConfirmationButtons.CONFIRM_CANCEL;
}
title: string;
message: string;
data: any = {};//default is empty
targetId: ConfirmationTargets = ConfirmationTargets.EMPTY;
param: string;
confirmOnly: boolean;
buttons: ConfirmationButtons;
}

View File

@ -0,0 +1,50 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Directive, OnChanges, Input, SimpleChanges } from '@angular/core';
import { NG_VALIDATORS, Validator, Validators, ValidatorFn, AbstractControl } from '@angular/forms';
@Directive({
selector: '[dateValidator]',
providers: [{provide: NG_VALIDATORS, useExisting: DateValidatorDirective, multi: true}]
})
export class DateValidatorDirective implements Validator, OnChanges {
@Input() dateValidator: string;
private valFn = Validators.nullValidator;
ngOnChanges(changes: SimpleChanges): void {
const change = changes['dateValidator'];
if (change) {
this.valFn = dateValidator();
} else {
this.valFn = Validators.nullValidator;
}
}
validate(control: AbstractControl): {[key: string]: any} {
return this.valFn(control);
}
}
export function dateValidator(): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
let controlValue = control.value;
let valid = true;
if(controlValue) {
const regYMD=/^(19|20)\d\d([- /.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/g;
const regDMY=/^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$/g;
valid = (regYMD.test(controlValue) || regDMY.test(controlValue));
}
return valid ? null : {'dateValidator': { value: controlValue }};
};
}

View File

@ -19,7 +19,7 @@ import { Policy } from '../../replication/policy';
import { ConfirmationDialogService } from '../../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message';
import { ConfirmationState, ConfirmationTargets } from '../../shared/shared.const';
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../../shared/shared.const';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
@ -135,7 +135,8 @@ export class ListPolicyComponent implements OnDestroy {
'REPLICATION.DELETION_SUMMARY',
policy.name,
policy.id,
ConfirmationTargets.POLICY);
ConfirmationTargets.POLICY,
ConfirmationButtons.DELETE_CANCEL);
this.deletionDialogService.openComfirmDialog(deletionMessage);
}

View File

@ -1,6 +1,6 @@
<clr-datagrid (clrDgRefresh)="refresh($event)">
<clr-dg-column>{{'PROJECT.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.PUBLIC_OR_PRIVATE' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.ACCESS_LEVEL' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-row *clrDgItems="let p of projects" [clrDgItem]="p">

View File

@ -67,6 +67,9 @@ export const CookieKeyOfAdmiral = "admiral.endpoint.latest";
export const enum ConfirmationState {
NA, CONFIRMED, CANCEL
}
export const enum ConfirmationButtons {
CONFIRM_CANCEL, YES_NO, DELETE_CANCEL, CLOSE
}
export const ProjectTypes = { 0: 'PROJECT.MY_PROJECTS', 1: 'PROJECT.PUBLIC_PROJECTS' };
export const RoleInfo = { 1: 'MEMBER.PROJECT_ADMIN', 2: 'MEMBER.DEVELOPER', 3: 'MEMBER.GUEST' };

View File

@ -54,6 +54,7 @@ import { MessageHandlerService } from './message-handler/message-handler.service
import { EmailValidatorDirective } from './email.directive';
import { GaugeComponent } from './gauge/gauge.component';
import { StatisticHandler } from './statictics/statistic-handler.service';
import { DateValidatorDirective } from '../shared/date-validator.directive';
@NgModule({
imports: [
@ -78,7 +79,8 @@ import { StatisticHandler } from './statictics/statistic-handler.service';
ListProjectROComponent,
ListRepositoryROComponent,
EmailValidatorDirective,
GaugeComponent
GaugeComponent,
DateValidatorDirective
],
exports: [
CoreModule,
@ -99,7 +101,8 @@ import { StatisticHandler } from './statictics/statistic-handler.service';
ListProjectROComponent,
ListRepositoryROComponent,
EmailValidatorDirective,
GaugeComponent
GaugeComponent,
DateValidatorDirective
],
providers: [
SessionService,

View File

@ -21,7 +21,7 @@ import { NewUserModalComponent } from './new-user-modal.component';
import { TranslateService } from '@ngx-translate/core';
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../shared/confirmation-dialog/confirmation-message';
import { ConfirmationState, ConfirmationTargets } from '../shared/shared.const'
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../shared/shared.const'
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
import { SessionService } from '../shared/session.service';
@ -188,7 +188,8 @@ export class UserComponent implements OnInit, OnDestroy {
"USER.DELETION_SUMMARY",
user.username,
user,
ConfirmationTargets.USER
ConfirmationTargets.USER,
ConfirmationButtons.DELETE_CANCEL
);
this.deletionDialogService.openComfirmDialog(msg);
}

View File

@ -124,6 +124,7 @@
"NAME": "Project Name",
"ROLE": "Role",
"PUBLIC_OR_PRIVATE": "Public",
"ACCESS_LEVEL": "Access Level",
"REPO_COUNT": "Repositories Count",
"CREATION_TIME": "Creation Time",
"PUBLIC": "Public",
@ -197,7 +198,8 @@
"ADVANCED": "Advanced",
"SIMPLE": "Simple",
"ITEMS": "item(s)",
"FILTER_PLACEHOLDER": "Filter Logs"
"FILTER_PLACEHOLDER": "Filter Logs",
"INVALID_DATE": "Invalid date."
},
"REPLICATION": {
"REPLICATION_RULE": "Replication Rule",
@ -265,7 +267,8 @@
"CANNOT_EDIT": "Replication rule cannot be changed while it is enabled.",
"POLICY_ALREADY_EXISTS": "Replication rule already exists.",
"FAILED_TO_DELETE_POLICY_ENABLED": "Cannot delete rule: rule has unfinished job(s) or rule is enabled.",
"FOUND_ERROR_IN_JOBS": "Found errors in the replication job(s), please check."
"FOUND_ERROR_IN_JOBS": "Found errors in the replication job(s), please check.",
"INVALID_DATE": "Invalid date."
},
"DESTINATION": {
"NEW_ENDPOINT": "New Endpoint",

View File

@ -124,6 +124,7 @@
"NAME": "Nombre del Proyecto",
"ROLE": "Rol",
"PUBLIC_OR_PRIVATE": "Público",
"ACCESS_LEVEL": "Nivel de acceso",
"REPO_COUNT": "Contador de repositorios",
"CREATION_TIME": "Fecha de creación",
"PUBLIC": "Público",
@ -197,7 +198,8 @@
"ADVANCED": "Avanzado",
"SIMPLE": "Simple",
"ITEMS": "elemento(s)",
"FILTER_PLACEHOLDER": "Filtrar logs"
"FILTER_PLACEHOLDER": "Filtrar logs",
"INVALID_DATE": "Fecha invalida."
},
"REPLICATION": {
"REPLICATION_RULE": "Reglas de Replicación",
@ -265,7 +267,8 @@
"CANNOT_EDIT": "La regla de replicación no se puede cambiar mientras esté activa.",
"POLICY_ALREADY_EXISTS": "La regla de replicación ya existe.",
"FAILED_TO_DELETE_POLICY_ENABLED": "No se puede eliminar la regla: tiene trabajo(s) sin finalizar o está activa.",
"FOUND_ERROR_IN_JOBS": "Se han encontrado errores en el trabajo de replicación. Por favor, compruébelos."
"FOUND_ERROR_IN_JOBS": "Se han encontrado errores en el trabajo de replicación. Por favor, compruébelos.",
"INVALID_DATE": "Fecha invalida."
},
"DESTINATION": {
"NEW_ENDPOINT": "Nuevo Endpoint",

View File

@ -124,6 +124,7 @@
"NAME": "项目名称",
"ROLE": "角色",
"PUBLIC_OR_PRIVATE": "公开",
"ACCESS_LEVEL": "访问级别",
"REPO_COUNT": "镜像仓库数",
"CREATION_TIME": "创建时间",
"PUBLIC": "公开",
@ -197,7 +198,8 @@
"ADVANCED": "高级检索",
"SIMPLE": "简单检索",
"ITEMS": "条记录",
"FILTER_PLACEHOLDER": "过滤日志"
"FILTER_PLACEHOLDER": "过滤日志",
"INVALID_DATE": "无效日期。"
},
"REPLICATION": {
"REPLICATION_RULE": "复制规则",
@ -265,7 +267,8 @@
"CANNOT_EDIT": "当复制规则启用时无法修改。",
"POLICY_ALREADY_EXISTS": "规则已存在。",
"FAILED_TO_DELETE_POLICY_ENABLED": "删除复制规则失败: 仍有未完成的任务或规则未停用。",
"FOUND_ERROR_IN_JOBS": "复制任务中包含错误,请检查。"
"FOUND_ERROR_IN_JOBS": "复制任务中包含错误,请检查。",
"INVALID_DATE": "无效日期。"
},
"DESTINATION": {
"NEW_ENDPOINT": "新建目标",