mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-27 19:17:47 +01:00
UI enhancement for replication namespace (#14818)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
a6d92ca807
commit
eec3619df1
@ -0,0 +1,15 @@
|
||||
export enum Flatten_Level {
|
||||
NO_FLATTING = 0,
|
||||
FLATTEN_LEVEl_1 = 1,
|
||||
FLATTEN_LEVEl_2 = 2,
|
||||
FLATTEN_LEVEl_3 = 3,
|
||||
FLATTEN_ALL = -1
|
||||
}
|
||||
|
||||
export const Flatten_I18n_MAP = {
|
||||
[Flatten_Level.NO_FLATTING]: 'REPLICATION.NO_FLATTING',
|
||||
[Flatten_Level.FLATTEN_LEVEl_1]: 'REPLICATION.FLATTEN_LEVEL_1',
|
||||
[Flatten_Level.FLATTEN_LEVEl_2]: 'REPLICATION.FLATTEN_LEVEL_2',
|
||||
[Flatten_Level.FLATTEN_LEVEl_3]: 'REPLICATION.FLATTEN_LEVEL_3',
|
||||
[Flatten_Level.FLATTEN_ALL]: 'REPLICATION.FLATTEN_ALL',
|
||||
};
|
@ -151,19 +151,48 @@
|
||||
</div>
|
||||
</div>
|
||||
<!--destination namespaces -->
|
||||
<clr-input-container>
|
||||
<label>{{'REPLICATION.DEST_NAMESPACE' | translate}}
|
||||
<clr-tooltip>
|
||||
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
|
||||
<clr-tooltip-content clrPosition="top-left" clrSize="md" *clrIfOpen>
|
||||
<span>{{'TOOLTIP.DESTINATION_NAMESPACE' | translate}}</span>
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</label>
|
||||
<input clrInput formControlName="dest_namespace" type="text" id="dest_namespace" pattern="^[a-z0-9]+(?:[/._-][a-z0-9]+)*$"
|
||||
class="inputWidth" maxlength="255">
|
||||
<clr-control-error *ngIf='ruleForm.controls.dest_namespace.touched && ruleForm.controls.dest_namespace.invalid'>{{'REPLICATION.DESTINATION_NAME_TOOLTIP' | translate}}</clr-control-error>
|
||||
</clr-input-container>
|
||||
<div class="clr-form-control">
|
||||
<label for="dest_namespace" class="clr-control-label">{{'REPLICATION.DESTINATION' | translate}}</label>
|
||||
<div class="clr-control-container" [class.clr-error]="ruleForm.controls.dest_namespace.touched && ruleForm.controls.dest_namespace.invalid">
|
||||
<div class="clr-input-wrapper">
|
||||
<label class="sub-label">{{'REPLICATION.NAMESPACE' | translate}}:</label>
|
||||
<input autocomplete="off" class="clr-input" formControlName="dest_namespace" type="text" id="dest_namespace" pattern="^[a-z0-9]+(?:[/._-][a-z0-9]+)*$"
|
||||
maxlength="255">
|
||||
<clr-tooltip class="des-tooltip">
|
||||
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
|
||||
<clr-tooltip-content clrPosition="top-left" clrSize="md" *clrIfOpen>
|
||||
<span>{{'TOOLTIP.DESTINATION_NAMESPACE' | translate}}</span>
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</div>
|
||||
<clr-control-error class="margin-left-90px" *ngIf="ruleForm.controls.dest_namespace.touched && ruleForm.controls.dest_namespace.invalid">
|
||||
{{'REPLICATION.DESTINATION_NAME_TOOLTIP' | translate}}
|
||||
</clr-control-error>
|
||||
</div>
|
||||
</div>
|
||||
<!--destination namespaces -->
|
||||
<div class="clr-form-control">
|
||||
<label for="dest_namespace_replace_count" class="clr-control-label"></label>
|
||||
<div class="clr-control-container" [class.clr-error]="ruleForm.controls.dest_namespace_replace_count.touched && ruleForm.controls.dest_namespace_replace_count.invalid">
|
||||
<div class="input-width flex">
|
||||
<div class="clr-select-wrapper">
|
||||
<label class="sub-label">{{'REPLICATION.REPO_FLATTENING' | translate}}:</label>
|
||||
<select id="dest_namespace_replace_count" formControlName="dest_namespace_replace_count" class="clr-select count-type">
|
||||
<option *ngFor="let item of flattenLevelMap | keyvalue"
|
||||
[value]="item.key">{{item.value | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="clr-input-wrapper">
|
||||
<clr-tooltip class="des-tooltip">
|
||||
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
|
||||
<clr-tooltip-content clrPosition="top-left" clrSize="md" *clrIfOpen>
|
||||
{{'REPLICATION.FLATTEN_LEVEL_TIP' | translate}}
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--Trigger-->
|
||||
<div class="clr-form-control">
|
||||
<label class="clr-control-label required">{{'REPLICATION.TRIGGER_MODE' | translate}}</label>
|
||||
@ -216,13 +245,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loading-center">
|
||||
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="ruleBtnCancel" class="btn btn-outline" [disabled]="this.inProgress" (click)="onCancel()">{{ 'BUTTON.CANCEL' | translate }}</button>
|
||||
<button type="submit" id="ruleBtnOk" class="btn btn-primary" (click)="onSubmit()" [disabled]="!isValid || !hasFormChange()">{{ 'BUTTON.SAVE' | translate }}</button>
|
||||
<button type="button" id="ruleBtnCancel" class="btn btn-outline" [disabled]="inProgress" (click)="onCancel()">{{ 'BUTTON.CANCEL' | translate }}</button>
|
||||
<button type="submit" id="ruleBtnOk" class="btn btn-primary" [clrLoading]="inProgress" (click)="onSubmit()" [disabled]="!isValid || !hasFormChange()">{{ 'BUTTON.SAVE' | translate }}</button>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
@ -286,3 +286,21 @@ clr-modal {
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.sub-label {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.clr-control-label {
|
||||
width: 8.6rem;
|
||||
}
|
||||
.count {
|
||||
width: 34px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.des-tooltip {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.count-type {
|
||||
width: 158px;
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
||||
|
||||
it("Should open modal to edit replication rule", fakeAsync( () => {
|
||||
fixture.detectChanges();
|
||||
comp.openCreateEditRule(mockRule.id);
|
||||
comp.openCreateEditRule(mockRule);
|
||||
fixture.detectChanges();
|
||||
tick(5000);
|
||||
const ruleNameInput: HTMLInputElement = fixture.nativeElement.querySelector("#ruleName");
|
||||
|
@ -33,9 +33,13 @@ import { cronRegex } from "../../../../../shared/units/utils";
|
||||
import { FilterType } from "../../../../../shared/entities/shared.const";
|
||||
import { RegistryService } from "../../../../../../../ng-swagger-gen/services/registry.service";
|
||||
import { Registry } from "../../../../../../../ng-swagger-gen/models/registry";
|
||||
import { Label } from "../../../../../../../ng-swagger-gen/models/label";
|
||||
import { LabelService } from "../../../../../../../ng-swagger-gen/services/label.service";
|
||||
import { Flatten_I18n_MAP, Flatten_Level } from "../../replication";
|
||||
|
||||
const PREFIX: string = '0 ';
|
||||
const PAGE_SIZE: number = 100;
|
||||
|
||||
@Component({
|
||||
selector: "hbr-create-edit-rule",
|
||||
templateUrl: "./create-edit-rule.component.html",
|
||||
@ -77,12 +81,14 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
@Output() reload = new EventEmitter<boolean>();
|
||||
|
||||
@ViewChild(InlineAlertComponent, {static: true}) inlineAlert: InlineAlertComponent;
|
||||
flattenLevelMap = Flatten_I18n_MAP;
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private repService: ReplicationService,
|
||||
private endpointService: RegistryService,
|
||||
private errorHandler: ErrorHandler,
|
||||
private translateService: TranslateService,
|
||||
private labelService: LabelService,
|
||||
) {
|
||||
this.createForm();
|
||||
}
|
||||
@ -95,8 +101,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
this.supportedFilters = adapter.supported_resource_filters;
|
||||
this.supportedFilters.forEach(element => {
|
||||
this.filters.push(this.initFilter(element.type));
|
||||
// get supportedFilterLabels labels from supportedFilters
|
||||
this.getLabelListFromAdapter(element);
|
||||
});
|
||||
this.supportedTriggers = adapter.supported_triggers;
|
||||
this.ruleForm.get("trigger").get("type").setValue(this.supportedTriggers[0]);
|
||||
@ -142,6 +146,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.getAllLabels();
|
||||
this.getAllRegistries();
|
||||
this.nameChecker
|
||||
.pipe(debounceTime(300))
|
||||
@ -227,6 +232,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
src_registry: new FormControl(),
|
||||
dest_registry: new FormControl(),
|
||||
dest_namespace: "",
|
||||
dest_namespace_replace_count: -1,
|
||||
trigger: this.fb.group({
|
||||
type: '',
|
||||
trigger_settings: this.fb.group({
|
||||
@ -261,7 +267,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
},
|
||||
deletion: false,
|
||||
enabled: true,
|
||||
override: true
|
||||
override: true,
|
||||
dest_namespace_replace_count: Flatten_Level.FLATTEN_LEVEl_1
|
||||
});
|
||||
this.isPushMode = true;
|
||||
}
|
||||
@ -276,6 +283,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
name: rule.name,
|
||||
description: rule.description,
|
||||
dest_namespace: rule.dest_namespace,
|
||||
dest_namespace_replace_count: rule.dest_namespace_replace_count,
|
||||
src_registry: rule.src_registry,
|
||||
dest_registry: rule.dest_registry,
|
||||
trigger: rule.trigger,
|
||||
@ -284,7 +292,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
override: rule.override
|
||||
});
|
||||
let filtersArray = this.getFilterArray(rule);
|
||||
|
||||
this.noSelectedEndpoint = false;
|
||||
this.setFilter(filtersArray);
|
||||
this.copyUpdateForm = clone(this.ruleForm.value);
|
||||
@ -359,6 +366,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
// add new Replication rule
|
||||
this.inProgress = true;
|
||||
let copyRuleForm: ReplicationRule = this.ruleForm.value;
|
||||
copyRuleForm.dest_namespace_replace_count = copyRuleForm.dest_namespace_replace_count
|
||||
? parseInt(copyRuleForm.dest_namespace_replace_count.toString(), 10) : 0;
|
||||
if (this.isPushMode) {
|
||||
copyRuleForm.src_registry = null;
|
||||
} else {
|
||||
@ -404,26 +413,38 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
}
|
||||
openCreateEditRule(ruleId?: number | string): void {
|
||||
openCreateEditRule(rule?: ReplicationRule): void {
|
||||
this.formReset();
|
||||
this.copyUpdateForm = clone(this.ruleForm.value);
|
||||
this.inlineAlert.close();
|
||||
this.noSelectedEndpoint = true;
|
||||
this.isRuleNameValid = true;
|
||||
this.supportedFilterLabels = [];
|
||||
|
||||
|
||||
this.policyId = -1;
|
||||
this.createEditRuleOpened = true;
|
||||
this.noEndpointInfo = "";
|
||||
if (this.targetList.length === 0) {
|
||||
this.noEndpointInfo = "REPLICATION.NO_ENDPOINT_INFO";
|
||||
}
|
||||
if (ruleId) {
|
||||
if (rule) {
|
||||
if (this.supportedFilterLabels && this.supportedFilterLabels.length) {
|
||||
this.supportedFilterLabels.forEach((label, index) => {
|
||||
if (rule.filters && rule.filters.length) {
|
||||
rule.filters.forEach(f => {
|
||||
if (f.type === FilterType.LABEL && f.value && f.value.length) {
|
||||
f.value.forEach(name => {
|
||||
if (label.name === name) {
|
||||
this.supportedFilterLabels[index].select = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
this.onGoing = true;
|
||||
this.policyId = +ruleId;
|
||||
this.policyId = +rule.id;
|
||||
this.headerTitle = "REPLICATION.EDIT_POLICY_TITLE";
|
||||
this.repService.getReplicationRule(ruleId)
|
||||
this.repService.getReplicationRule(rule.id)
|
||||
.subscribe((ruleInfo) => {
|
||||
let srcRegistryId = ruleInfo.src_registry.id;
|
||||
this.repService.getRegistryInfo(srcRegistryId)
|
||||
@ -458,58 +479,11 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
this.setFilter([]);
|
||||
this.supportedFilters.forEach(element => {
|
||||
this.filters.push(this.initFilter(element.type));
|
||||
// get supportedFilterLabels labels from supportedFilters
|
||||
this.getLabelListFromAdapter(element);
|
||||
// only when edit replication rule
|
||||
if (ruleInfo && ruleInfo.filters && this.supportedFilterLabels.length ) {
|
||||
this.getLabelListFromRuleInfo(ruleInfo);
|
||||
}
|
||||
});
|
||||
|
||||
this.supportedTriggers = adapter.supported_triggers;
|
||||
this.ruleForm.get("trigger").get("type").setValue(this.supportedTriggers[0]);
|
||||
}
|
||||
getLabelListFromAdapter(supportedFilter) {
|
||||
if (supportedFilter.type === FilterType.LABEL && supportedFilter.values) {
|
||||
this.supportedFilterLabels = [];
|
||||
supportedFilter.values.forEach( value => {
|
||||
this.supportedFilterLabels.push({
|
||||
name: value,
|
||||
color: '#FFFFFF',
|
||||
select: false,
|
||||
scope: 'g'
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
getLabelListFromRuleInfo(ruleInfo) {
|
||||
let labelValueObj = ruleInfo.filters.find((currentValue) => {
|
||||
return currentValue.type === FilterType.LABEL;
|
||||
});
|
||||
if (labelValueObj) {
|
||||
for (const labelValue of labelValueObj.value) {
|
||||
let flagLabel = this.supportedFilterLabels.every((currentValue) => {
|
||||
return currentValue.name !== labelValue;
|
||||
});
|
||||
if (flagLabel) {
|
||||
this.supportedFilterLabels = [
|
||||
{
|
||||
name: labelValue,
|
||||
color: '#FFFFFF',
|
||||
select: true,
|
||||
scope: 'g'
|
||||
}, ...this.supportedFilterLabels];
|
||||
}
|
||||
//
|
||||
for (const labelObj of this.supportedFilterLabels) {
|
||||
if (labelObj.name === labelValue) {
|
||||
labelObj.select = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
close(): void {
|
||||
this.createEditRuleOpened = false;
|
||||
}
|
||||
@ -612,4 +586,56 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
}
|
||||
getAllLabels(): void {
|
||||
// get all global labels
|
||||
this.labelService.ListLabelsResponse({
|
||||
pageSize: PAGE_SIZE,
|
||||
page: 1,
|
||||
scope: 'g',
|
||||
}).subscribe(res => {
|
||||
if (res.headers) {
|
||||
const xHeader: string = res.headers.get("X-Total-Count");
|
||||
const totalCount = parseInt(xHeader, 0);
|
||||
let arr = res.body || [];
|
||||
if (totalCount <= PAGE_SIZE) { // already gotten all global labels
|
||||
if (arr && arr.length) {
|
||||
arr.forEach(data => {
|
||||
this.supportedFilterLabels.push({
|
||||
name: data.name,
|
||||
color: data.color ? data.color : '#FFFFFF',
|
||||
select: false,
|
||||
scope: 'g'
|
||||
});
|
||||
});
|
||||
}
|
||||
} else { // get all the global labels in specified times
|
||||
const times: number = Math.ceil(totalCount / PAGE_SIZE);
|
||||
const observableList: Observable<Label[]>[] = [];
|
||||
for (let i = 2; i <= times; i++) {
|
||||
observableList.push(this.labelService.ListLabels({
|
||||
page: i,
|
||||
pageSize: PAGE_SIZE,
|
||||
scope: 'g',
|
||||
}));
|
||||
}
|
||||
forkJoin(observableList)
|
||||
.subscribe(response => {
|
||||
if (response && response.length) {
|
||||
response.forEach(item => {
|
||||
arr = arr.concat(item);
|
||||
});
|
||||
arr.forEach(data => {
|
||||
this.supportedFilterLabels.push({
|
||||
name: data.name,
|
||||
color: data.color ? data.color : '#FFFFFF',
|
||||
select: false,
|
||||
scope: 'g'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
<clr-dg-column class="col-width">{{'REPLICATION.SRC_REGISTRY' | translate}}</clr-dg-column>
|
||||
<clr-dg-column class="col-width">{{'REPLICATION.REPLICATION_MODE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column class="min-width">{{'REPLICATION.DESTINATION_NAMESPACE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.DES_REPO_FLATTENING' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.REPLICATION_TRIGGER' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'description'">{{'REPLICATION.DESCRIPTION' | translate}}</clr-dg-column>
|
||||
<clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder>
|
||||
@ -79,6 +80,7 @@
|
||||
<clr-dg-cell class="min-width">
|
||||
{{p.dest_registry ? p.dest_registry.name : ''}} : {{p.dest_namespace? p.dest_namespace: '-'}}
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{(getFlattenLevelString(p.dest_namespace_replace_count)) | translate}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{p.trigger ? p.trigger.type : ''}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
{{p.description ? trancatedDescription(p.description) : '-'}}
|
||||
|
@ -6,7 +6,7 @@
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
.min-width {
|
||||
width: 224px;
|
||||
width: 236px;
|
||||
}
|
||||
.col-width {
|
||||
width: 140px;
|
||||
@ -20,4 +20,4 @@
|
||||
}
|
||||
.margin-right-2px {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import { errorHandler } from "../../../../../shared/units/shared.utils";
|
||||
import { ConfirmationAcknowledgement } from "../../../../global-confirmation-dialog/confirmation-state-message";
|
||||
import { ConfirmationMessage } from "../../../../global-confirmation-dialog/confirmation-message";
|
||||
import { HELM_HUB } from "../../../../../shared/services/endpoint.service";
|
||||
import { Flatten_I18n_MAP } from "../../replication";
|
||||
@Component({
|
||||
selector: "hbr-list-replication-rule",
|
||||
templateUrl: "./list-replication-rule.component.html",
|
||||
@ -261,4 +262,10 @@ export class ListReplicationRuleComponent {
|
||||
isHelmHub(srcRegistry: any): boolean {
|
||||
return srcRegistry && srcRegistry.type === HELM_HUB;
|
||||
}
|
||||
getFlattenLevelString(level: number) {
|
||||
if (level !== null && Flatten_I18n_MAP[level]) {
|
||||
return Flatten_I18n_MAP[level];
|
||||
}
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
||||
// edit replication rule
|
||||
openEditRule(rule: ReplicationRule) {
|
||||
if (rule) {
|
||||
this.createEditPolicyComponent.openCreateEditRule(rule.id);
|
||||
this.createEditPolicyComponent.openCreateEditRule(rule);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,7 @@ export interface ReplicationRule extends Base {
|
||||
dest_registry?: any;
|
||||
src_namespaces: string[];
|
||||
dest_namespace?: string;
|
||||
dest_namespace_replace_count?: number;
|
||||
enabled: boolean;
|
||||
override: boolean;
|
||||
}
|
||||
|
@ -621,14 +621,23 @@
|
||||
"TAG": "Tag",
|
||||
"LABEL": "Label",
|
||||
"RESOURCE": "Ressource",
|
||||
"ENABLE_TITLE": "Aktiviere Regel",
|
||||
"ENABLE_SUMMARY": "Soll die Regel {{param}} aktiviert werden?",
|
||||
"DISABLE_TITLE": "Deaktiviere Regel",
|
||||
"DISABLE_SUMMARY": "Soll die Regel {{param}} deaktiviert werden?",
|
||||
"ENABLE_SUCCESS": "Aktivieren der Regel erfolgreich",
|
||||
"ENABLE_TITLE": "Aktiviere Regel",
|
||||
"ENABLE_SUMMARY": "Soll die Regel {{param}} aktiviert werden?",
|
||||
"DISABLE_TITLE": "Deaktiviere Regel",
|
||||
"DISABLE_SUMMARY": "Soll die Regel {{param}} deaktiviert werden?",
|
||||
"ENABLE_SUCCESS": "Aktivieren der Regel erfolgreich",
|
||||
"ENABLE_FAILED": "Aktivieren der Regel fehlgeschlagen",
|
||||
"DISABLE_SUCCESS": "Deaktivieren der Regel erfolgreich",
|
||||
"DISABLE_FAILED": "Deaktivieren der Regel fehlgeschlagen"
|
||||
"DISABLE_FAILED": "Deaktivieren der Regel fehlgeschlagen",
|
||||
"DES_REPO_FLATTENING": "Destination Repository Flattening",
|
||||
"NAMESPACE": "Namespace",
|
||||
"REPO_FLATTENING": "Flattening",
|
||||
"NO_FLATTING": "No Flatting",
|
||||
"FLATTEN_LEVEL_1": "Flatten 1 Level",
|
||||
"FLATTEN_LEVEL_2": "Flatten 2 Levels",
|
||||
"FLATTEN_LEVEL_3": "Flatten 3 Levels",
|
||||
"FLATTEN_ALL": "Flatten All Levels",
|
||||
"FLATTEN_LEVEL_TIP": "Reduce the nested repository structure when copying images. Default 'Flatten 1 Level' will replace the left most repository component with the destination namespace a/b/c/img -> ns/b/c/img. 'Flatten all Levels' is the legacy option used prior v2.3 resulting in a/b/c/img -> ns/img."
|
||||
},
|
||||
"DESTINATION": {
|
||||
"NEW_ENDPOINT": "Neuer Endpunkt",
|
||||
|
@ -545,7 +545,7 @@
|
||||
"DISABLE": "Disable",
|
||||
"REPLICATION_MODE": "Replication Mode",
|
||||
"SRC_REGISTRY": "Source registry",
|
||||
"DESTINATION_NAMESPACE": "Destination registry:Namespace",
|
||||
"DESTINATION_NAMESPACE": "Destination Registry:Namespace",
|
||||
"DESTINATION_NAME_IS_REQUIRED": "Endpoint name is required.",
|
||||
"NEW_DESTINATION": "New Endpoint",
|
||||
"DESTINATION_URL": "Endpoint URL",
|
||||
@ -628,7 +628,16 @@
|
||||
"ENABLE_SUCCESS": "Enabled rule successfully",
|
||||
"ENABLE_FAILED": "Enabling rule failed",
|
||||
"DISABLE_SUCCESS": "Disabled rule successfully",
|
||||
"DISABLE_FAILED": "Disabling rule failed"
|
||||
"DISABLE_FAILED": "Disabling rule failed",
|
||||
"DES_REPO_FLATTENING": "Destination Repository Flattening",
|
||||
"NAMESPACE": "Namespace",
|
||||
"REPO_FLATTENING": "Flattening",
|
||||
"NO_FLATTING": "No Flatting",
|
||||
"FLATTEN_LEVEL_1": "Flatten 1 Level",
|
||||
"FLATTEN_LEVEL_2": "Flatten 2 Levels",
|
||||
"FLATTEN_LEVEL_3": "Flatten 3 Levels",
|
||||
"FLATTEN_ALL": "Flatten All Levels",
|
||||
"FLATTEN_LEVEL_TIP": "Reduce the nested repository structure when copying images. Default 'Flatten 1 Level' will replace the left most repository component with the destination namespace a/b/c/img -> ns/b/c/img. 'Flatten all Levels' is the legacy option used prior v2.3 resulting in a/b/c/img -> ns/img."
|
||||
},
|
||||
"DESTINATION": {
|
||||
"NEW_ENDPOINT": "New Endpoint",
|
||||
|
@ -629,7 +629,16 @@
|
||||
"ENABLE_SUCCESS": "Enabled rule successfully",
|
||||
"ENABLE_FAILED": "Enabling rule failed",
|
||||
"DISABLE_SUCCESS": "Disabled rule successfully",
|
||||
"DISABLE_FAILED": "Disabling rule failed"
|
||||
"DISABLE_FAILED": "Disabling rule failed",
|
||||
"DES_REPO_FLATTENING": "Destination Repository Flattening",
|
||||
"NAMESPACE": "Namespace",
|
||||
"REPO_FLATTENING": "Flattening",
|
||||
"NO_FLATTING": "No Flatting",
|
||||
"FLATTEN_LEVEL_1": "Flatten 1 Level",
|
||||
"FLATTEN_LEVEL_2": "Flatten 2 Levels",
|
||||
"FLATTEN_LEVEL_3": "Flatten 3 Levels",
|
||||
"FLATTEN_ALL": "Flatten All Levels",
|
||||
"FLATTEN_LEVEL_TIP": "Reduce the nested repository structure when copying images. Default 'Flatten 1 Level' will replace the left most repository component with the destination namespace a/b/c/img -> ns/b/c/img. 'Flatten all Levels' is the legacy option used prior v2.3 resulting in a/b/c/img -> ns/img."
|
||||
},
|
||||
"DESTINATION": {
|
||||
"NEW_ENDPOINT": "Nuevo Endpoint",
|
||||
|
@ -618,7 +618,16 @@
|
||||
"ENABLE_SUCCESS": "Enabled rule successfully",
|
||||
"ENABLE_FAILED": "Enabling rule failed",
|
||||
"DISABLE_SUCCESS": "Disabled rule successfully",
|
||||
"DISABLE_FAILED": "Disabling rule failed"
|
||||
"DISABLE_FAILED": "Disabling rule failed",
|
||||
"DES_REPO_FLATTENING": "Destination Repository Flattening",
|
||||
"NAMESPACE": "Namespace",
|
||||
"REPO_FLATTENING": "Flattening",
|
||||
"NO_FLATTING": "No Flatting",
|
||||
"FLATTEN_LEVEL_1": "Flatten 1 Level",
|
||||
"FLATTEN_LEVEL_2": "Flatten 2 Levels",
|
||||
"FLATTEN_LEVEL_3": "Flatten 3 Levels",
|
||||
"FLATTEN_ALL": "Flatten All Levels",
|
||||
"FLATTEN_LEVEL_TIP": "Reduce the nested repository structure when copying images. Default 'Flatten 1 Level' will replace the left most repository component with the destination namespace a/b/c/img -> ns/b/c/img. 'Flatten all Levels' is the legacy option used prior v2.3 resulting in a/b/c/img -> ns/img."
|
||||
},
|
||||
"DESTINATION": {
|
||||
"NEW_ENDPOINT": "Nouveau Point Final",
|
||||
|
@ -628,7 +628,16 @@
|
||||
"ENABLE_SUCCESS": "Enabled rule successfully",
|
||||
"ENABLE_FAILED": "Enabling rule failed",
|
||||
"DISABLE_SUCCESS": "Disabled rule successfully",
|
||||
"DISABLE_FAILED": "Disabling rule failed"
|
||||
"DISABLE_FAILED": "Disabling rule failed",
|
||||
"DES_REPO_FLATTENING": "Destination Repository Flattening",
|
||||
"NAMESPACE": "Namespace",
|
||||
"REPO_FLATTENING": "Flattening",
|
||||
"NO_FLATTING": "No Flatting",
|
||||
"FLATTEN_LEVEL_1": "Flatten 1 Level",
|
||||
"FLATTEN_LEVEL_2": "Flatten 2 Levels",
|
||||
"FLATTEN_LEVEL_3": "Flatten 3 Levels",
|
||||
"FLATTEN_ALL": "Flatten All Levels",
|
||||
"FLATTEN_LEVEL_TIP": "Reduce the nested repository structure when copying images. Default 'Flatten 1 Level' will replace the left most repository component with the destination namespace a/b/c/img -> ns/b/c/img. 'Flatten all Levels' is the legacy option used prior v2.3 resulting in a/b/c/img -> ns/img."
|
||||
},
|
||||
"DESTINATION": {
|
||||
"NEW_ENDPOINT": "Novo Endpoint",
|
||||
|
@ -628,7 +628,16 @@
|
||||
"ENABLE_SUCCESS": "Enabled rule successfully",
|
||||
"ENABLE_FAILED": "Enabling rule failed",
|
||||
"DISABLE_SUCCESS": "Disabled rule successfully",
|
||||
"DISABLE_FAILED": "Disabling rule failed"
|
||||
"DISABLE_FAILED": "Disabling rule failed",
|
||||
"DES_REPO_FLATTENING": "Destination Repository Flattening",
|
||||
"NAMESPACE": "Namespace",
|
||||
"REPO_FLATTENING": "Flattening",
|
||||
"NO_FLATTING": "No Flatting",
|
||||
"FLATTEN_LEVEL_1": "Flatten 1 Level",
|
||||
"FLATTEN_LEVEL_2": "Flatten 2 Levels",
|
||||
"FLATTEN_LEVEL_3": "Flatten 3 Levels",
|
||||
"FLATTEN_ALL": "Flatten All Levels",
|
||||
"FLATTEN_LEVEL_TIP": "Reduce the nested repository structure when copying images. Default 'Flatten 1 Level' will replace the left most repository component with the destination namespace a/b/c/img -> ns/b/c/img. 'Flatten all Levels' is the legacy option used prior v2.3 resulting in a/b/c/img -> ns/img."
|
||||
},
|
||||
"DESTINATION": {
|
||||
"NEW_ENDPOINT": "Yeni Uç Nokta",
|
||||
|
@ -71,7 +71,7 @@
|
||||
"RESOURCE_FILTER": "过滤资源的类型。",
|
||||
"PUSH_BASED": "把资源由本地Harbor推送到远端仓库。",
|
||||
"PULL_BASED": "把资源由远端仓库拉取到本地Harbor。",
|
||||
"DESTINATION_NAMESPACE": "指定目的端名称空间。如果不填,资源会被放到和源相同的名称空间下。",
|
||||
"DESTINATION_NAMESPACE": "指定目标名称空间。如果不填,资源会被放到和源相同的名称空间下。",
|
||||
"OVERRIDE": "如果存在具有相同名称的资源,请指定是否覆盖目标上的资源。",
|
||||
"EMAIL": "请使用正确的邮箱地址,比如name@example.com。",
|
||||
"USER_NAME": "不能包含特殊字符且长度不能超过255。",
|
||||
@ -546,7 +546,7 @@
|
||||
"DISABLE": "停用",
|
||||
"REPLICATION_MODE": "复制模式",
|
||||
"SRC_REGISTRY": "源仓库",
|
||||
"DESTINATION_NAMESPACE": "目标仓库:命名空间",
|
||||
"DESTINATION_NAMESPACE": "目标仓库:名称空间",
|
||||
"DESTINATION_NAME_IS_REQUIRED": "目标名称为必填项。",
|
||||
"NEW_DESTINATION": "创建目标",
|
||||
"DESTINATION_URL": "目标URL",
|
||||
@ -573,6 +573,7 @@
|
||||
"ADVANCED": "高级检索",
|
||||
"STATUS": "状态",
|
||||
"OPERATION": "操作",
|
||||
"REPLICATION_TRIGGER": "触发器",
|
||||
"CREATION_TIME": "创建时间",
|
||||
"UPDATE_TIME": "更新时间",
|
||||
"END_TIME": "结束时间",
|
||||
@ -610,15 +611,15 @@
|
||||
"DELETE_ENABLED": "默认启用该规则",
|
||||
"NEW": "新增",
|
||||
"NAME_TOOLTIP": "项目名称由小写字符、数字和._-组成且至少2个字符并以字符或者数字开头。",
|
||||
"DESTINATION_NAME_TOOLTIP": "目标名称由小写字符、数字和._-/组成且至少2个字符并以字符或者数字开头。",
|
||||
"DESTINATION_NAME_TOOLTIP": "名称空间由小写字符、数字和._-/组成且至少2个字符并以字符或者数字开头。",
|
||||
"ACKNOWLEDGE": "确认",
|
||||
"RULE_DISABLED": "这个规则因为过滤选项中的标签被删除已经不能用了,更新过滤项以便重新启用规则。",
|
||||
"REPLI_MODE": "复制模式",
|
||||
"SOURCE_REGISTRY": "源Registry",
|
||||
"SOURCE_NAMESPACES": "源Namespace",
|
||||
"DEST_REGISTRY": "目的Registry",
|
||||
"DEST_NAMESPACE": "目的Namespace",
|
||||
"NAMESPACE_TOOLTIP": "Namespace名称由小写字符、数字和._-组成且至少2个字符并以字符或者数字开头。",
|
||||
"SOURCE_REGISTRY": "源仓库",
|
||||
"SOURCE_NAMESPACES": "源名称空间",
|
||||
"DEST_REGISTRY": "目标仓库",
|
||||
"DEST_NAMESPACE": "目标名称空间",
|
||||
"NAMESPACE_TOOLTIP": "名称空间名称由小写字符、数字和._-组成且至少2个字符并以字符或者数字开头。",
|
||||
"TAG": "Tag",
|
||||
"LABEL": "标签",
|
||||
"RESOURCE": "资源",
|
||||
@ -629,7 +630,16 @@
|
||||
"ENABLE_SUCCESS": "启用规则成功",
|
||||
"ENABLE_FAILED": "启用规则失败",
|
||||
"DISABLE_SUCCESS": "禁用规则成功",
|
||||
"DISABLE_FAILED": "禁用规则失败"
|
||||
"DISABLE_FAILED": "禁用规则失败",
|
||||
"DES_REPO_FLATTENING": "目标仓库扁平化",
|
||||
"NAMESPACE": "名称空间",
|
||||
"REPO_FLATTENING": "仓库扁平化",
|
||||
"NO_FLATTING": "无替换",
|
||||
"FLATTEN_LEVEL_1": "替换1级",
|
||||
"FLATTEN_LEVEL_2": "替换2级",
|
||||
"FLATTEN_LEVEL_3": "替换3级",
|
||||
"FLATTEN_ALL": "替换所有级",
|
||||
"FLATTEN_LEVEL_TIP": "此项用以在复制镜像时减少仓库的层级结构。默认值'替换1级'表示将用目标名称空间替换仓库的最左侧一级,例如:a/b/c/img -> namespace/b/c/img,其他替换层级以此类推。'替换所有级'是v2.3之前版本所使用的行为,它表示 a/b/c/img -> namespace/img。"
|
||||
},
|
||||
"DESTINATION": {
|
||||
"NEW_ENDPOINT": "新建目标",
|
||||
|
@ -625,7 +625,16 @@
|
||||
"ENABLE_SUCCESS": "Enabled rule successfully",
|
||||
"ENABLE_FAILED": "Enabling rule failed",
|
||||
"DISABLE_SUCCESS": "Disabled rule successfully",
|
||||
"DISABLE_FAILED": "Disabling rule failed"
|
||||
"DISABLE_FAILED": "Disabling rule failed",
|
||||
"DES_REPO_FLATTENING": "Destination Repository Flattening",
|
||||
"NAMESPACE": "Namespace",
|
||||
"REPO_FLATTENING": "Flattening",
|
||||
"NO_FLATTING": "No Flatting",
|
||||
"FLATTEN_LEVEL_1": "Flatten 1 Level",
|
||||
"FLATTEN_LEVEL_2": "Flatten 2 Levels",
|
||||
"FLATTEN_LEVEL_3": "Flatten 3 Levels",
|
||||
"FLATTEN_ALL": "Flatten All Levels",
|
||||
"FLATTEN_LEVEL_TIP": "Reduce the nested repository structure when copying images. Default 'Flatten 1 Level' will replace the left most repository component with the destination namespace a/b/c/img -> ns/b/c/img. 'Flatten all Levels' is the legacy option used prior v2.3 resulting in a/b/c/img -> ns/img."
|
||||
},
|
||||
"DESTINATION":{
|
||||
"NEW_ENDPOINT": "新建目標",
|
||||
|
Loading…
Reference in New Issue
Block a user