mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-27 12:46:03 +01:00
Add label filter in replication Ng
Signed-off-by: Yogi_Wang <yawang@vmware.com>
This commit is contained in:
parent
6d2d5a6a2a
commit
9c07caa1a6
@ -77,6 +77,27 @@
|
|||||||
<option *ngFor="let value of supportedFilters[i]?.values;" value="{{value}}">{{value}}</option>
|
<option *ngFor="let value of supportedFilters[i]?.values;" value="{{value}}">{{value}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="select resource-box" *ngIf="supportedFilters[i]?.type==='label'&& supportedFilters[i]?.style==='list'">
|
||||||
|
<div class="dropdown width-100" formArrayName="value">
|
||||||
|
<clr-dropdown class="width-100">
|
||||||
|
<button type="button" class="width-100 dropdown-toggle btn btn-link statistic-data label-text" clrDropdownTrigger>
|
||||||
|
<ng-template ngFor let-label [ngForOf]="filter.value.value" let-m="index">
|
||||||
|
<span class="label" *ngIf="m<1"> {{label}} </span>
|
||||||
|
</ng-template>
|
||||||
|
<span class="ellipsis" *ngIf="filter.value.value.length>1">···</span>
|
||||||
|
<div *ngFor="let label1 of filter.value.value;let k = index" hidden="true">
|
||||||
|
<input type="text" [formControlName]="k" #labelValue id="{{'label_'+ supportedFilters[i]?.type + '_' + label1}}" name="{{'label_'+ supportedFilters[i]?.type + '_' + label1}}" placeholder="select labels" >
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<clr-dropdown-menu class="width-100" clrPosition="bottom-left" *clrIfOpen>
|
||||||
|
<button type="button" class="dropdown-item" *ngFor="let value of supportedFilterLabels" (click)="stickLabel(value,i)">
|
||||||
|
<clr-icon shape="check" [hidden]="!value.select" class='pull-left'></clr-icon>
|
||||||
|
<div class='labelDiv'><hbr-label-piece [label]="value" [labelWidth]="130"></hbr-label-piece></div>
|
||||||
|
</button>
|
||||||
|
</clr-dropdown-menu>
|
||||||
|
</clr-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="resource-box" *ngIf="supportedFilters[i]?.style==='radio' && supportedFilters[i]?.values.length <= 1">
|
<div class="resource-box" *ngIf="supportedFilters[i]?.style==='radio' && supportedFilters[i]?.values.length <= 1">
|
||||||
<span>{{supportedFilters[i]?.values}}</span>
|
<span>{{supportedFilters[i]?.values}}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -85,6 +106,7 @@
|
|||||||
<clr-tooltip-content clrPosition="top-left" clrSize="md" *clrIfOpen>
|
<clr-tooltip-content clrPosition="top-left" clrSize="md" *clrIfOpen>
|
||||||
<span class="tooltip-content" *ngIf="supportedFilters[i]?.type==='name'">{{'TOOLTIP.NAME_FILTER' | translate}}</span>
|
<span class="tooltip-content" *ngIf="supportedFilters[i]?.type==='name'">{{'TOOLTIP.NAME_FILTER' | translate}}</span>
|
||||||
<span class="tooltip-content" *ngIf="supportedFilters[i]?.type==='tag'">{{'TOOLTIP.TAG_FILTER' | translate}}</span>
|
<span class="tooltip-content" *ngIf="supportedFilters[i]?.type==='tag'">{{'TOOLTIP.TAG_FILTER' | translate}}</span>
|
||||||
|
<span class="tooltip-content" *ngIf="supportedFilters[i]?.type==='label'">{{'TOOLTIP.LABEL_FILTER' | translate}}</span>
|
||||||
<span class="tooltip-content" *ngIf="supportedFilters[i]?.type==='resource'">{{'TOOLTIP.RESOURCE_FILTER' | translate}}</span>
|
<span class="tooltip-content" *ngIf="supportedFilters[i]?.type==='resource'">{{'TOOLTIP.RESOURCE_FILTER' | translate}}</span>
|
||||||
</clr-tooltip-content>
|
</clr-tooltip-content>
|
||||||
</clr-tooltip>
|
</clr-tooltip>
|
||||||
|
@ -269,3 +269,28 @@ clr-modal {
|
|||||||
.display-none{
|
.display-none{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.width-100 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.label-text {
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: normal;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #000;
|
||||||
|
height: 1.2rem;
|
||||||
|
margin: 0 !important;
|
||||||
|
line-height: 1rem;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 6px;
|
||||||
|
outline: none;
|
||||||
|
border-bottom: 1px solid rgb(154, 154, 154);
|
||||||
|
}
|
||||||
|
.labelDiv {
|
||||||
|
padding-left: 26px;
|
||||||
|
}
|
||||||
|
.ellipsis {
|
||||||
|
margin-left: 0.2rem;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
@ -67,6 +67,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
cronString: string;
|
cronString: string;
|
||||||
supportedTriggers: string[];
|
supportedTriggers: string[];
|
||||||
supportedFilters: Filter[];
|
supportedFilters: Filter[];
|
||||||
|
supportedFilterLabels: { name: string; color: string; select: boolean; scope: string; }[] = [];
|
||||||
|
|
||||||
@Input() withAdmiral: boolean;
|
@Input() withAdmiral: boolean;
|
||||||
|
|
||||||
@Output() goToRegistry = new EventEmitter<any>();
|
@Output() goToRegistry = new EventEmitter<any>();
|
||||||
@ -92,6 +94,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
this.supportedFilters = adapter.supported_resource_filters;
|
this.supportedFilters = adapter.supported_resource_filters;
|
||||||
this.supportedFilters.forEach(element => {
|
this.supportedFilters.forEach(element => {
|
||||||
this.filters.push(this.initFilter(element.type));
|
this.filters.push(this.initFilter(element.type));
|
||||||
|
// get supportedFilterLabels labels from supportedFilters
|
||||||
|
this.getLabelListFromAdapter(element);
|
||||||
});
|
});
|
||||||
this.supportedTriggers = adapter.supported_triggers;
|
this.supportedTriggers = adapter.supported_triggers;
|
||||||
this.ruleForm.get("trigger").get("type").setValue(this.supportedTriggers[0]);
|
this.ruleForm.get("trigger").get("type").setValue(this.supportedTriggers[0]);
|
||||||
@ -261,15 +265,33 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get filters(): FormArray {
|
get filters(): FormArray {
|
||||||
|
console.log(this.ruleForm.get("filters"));
|
||||||
return this.ruleForm.get("filters") as FormArray;
|
return this.ruleForm.get("filters") as FormArray;
|
||||||
}
|
}
|
||||||
setFilter(filters: Filter[]) {
|
setFilter(filters: Filter[]) {
|
||||||
const filterFGs = filters.map(filter => this.fb.group(filter));
|
const filterFGs = filters.map(filter => {
|
||||||
|
if (filter.type === 'label') {
|
||||||
|
let fbLabel = this.fb.group({
|
||||||
|
type: 'label'
|
||||||
|
});
|
||||||
|
let filterLabel = this.fb.array(filter.value);
|
||||||
|
fbLabel.setControl('value', filterLabel);
|
||||||
|
return fbLabel;
|
||||||
|
} else {
|
||||||
|
return this.fb.group(filter);
|
||||||
|
}
|
||||||
|
});
|
||||||
const filterFormArray = this.fb.array(filterFGs);
|
const filterFormArray = this.fb.array(filterFGs);
|
||||||
this.ruleForm.setControl("filters", filterFormArray);
|
this.ruleForm.setControl("filters", filterFormArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
initFilter(name: string) {
|
initFilter(name: string) {
|
||||||
|
if (name === 'label') {
|
||||||
|
const labelArray = this.fb.array([]);
|
||||||
|
const labelControl = this.fb.group({type: name});
|
||||||
|
labelControl.setControl('value', labelArray);
|
||||||
|
return labelControl;
|
||||||
|
}
|
||||||
return this.fb.group({
|
return this.fb.group({
|
||||||
type: name,
|
type: name,
|
||||||
value: ''
|
value: ''
|
||||||
@ -314,7 +336,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
let filters: any = copyRuleForm.filters;
|
let filters: any = copyRuleForm.filters;
|
||||||
// remove the filters which user not set.
|
// remove the filters which user not set.
|
||||||
for (let i = filters.length - 1; i >= 0; i--) {
|
for (let i = filters.length - 1; i >= 0; i--) {
|
||||||
if (filters[i].value === "") {
|
if (filters[i].value === "" || (filters[i].value instanceof Array
|
||||||
|
&& filters[i].value.length === 0)) {
|
||||||
copyRuleForm.filters.splice(i, 1);
|
copyRuleForm.filters.splice(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,6 +379,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
this.inlineAlert.close();
|
this.inlineAlert.close();
|
||||||
this.noSelectedEndpoint = true;
|
this.noSelectedEndpoint = true;
|
||||||
this.isRuleNameValid = true;
|
this.isRuleNameValid = true;
|
||||||
|
this.supportedFilterLabels = [];
|
||||||
|
|
||||||
|
|
||||||
this.policyId = -1;
|
this.policyId = -1;
|
||||||
this.createEditRuleOpened = true;
|
this.createEditRuleOpened = true;
|
||||||
@ -373,7 +398,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
this.repService.getRegistryInfo(srcRegistryId)
|
this.repService.getRegistryInfo(srcRegistryId)
|
||||||
.pipe(finalize(() => (this.onGoing = false)))
|
.pipe(finalize(() => (this.onGoing = false)))
|
||||||
.subscribe(adapter => {
|
.subscribe(adapter => {
|
||||||
this.setFilterAndTrigger(adapter);
|
this.setFilterAndTrigger(adapter, ruleInfo);
|
||||||
this.updateRuleFormAndCopyUpdateForm(ruleInfo);
|
this.updateRuleFormAndCopyUpdateForm(ruleInfo);
|
||||||
}, (error: any) => {
|
}, (error: any) => {
|
||||||
this.inlineAlert.showInlineError(error);
|
this.inlineAlert.showInlineError(error);
|
||||||
@ -397,17 +422,63 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilterAndTrigger(adapter) {
|
setFilterAndTrigger(adapter, ruleInfo?) {
|
||||||
this.supportedFilters = adapter.supported_resource_filters;
|
this.supportedFilters = adapter.supported_resource_filters;
|
||||||
this.setFilter([]);
|
this.setFilter([]);
|
||||||
this.supportedFilters.forEach(element => {
|
this.supportedFilters.forEach(element => {
|
||||||
this.filters.push(this.initFilter(element.type));
|
this.filters.push(this.initFilter(element.type));
|
||||||
|
// get supportedFilterLabels labels from supportedFilters
|
||||||
|
this.getLabelListFromAdapter(element);
|
||||||
|
// only when edit replication rule
|
||||||
|
if (ruleInfo && this.supportedFilterLabels.length) {
|
||||||
|
this.getLabelListFromRuleInfo(ruleInfo);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.supportedTriggers = adapter.supported_triggers;
|
this.supportedTriggers = adapter.supported_triggers;
|
||||||
this.ruleForm.get("trigger").get("type").setValue(this.supportedTriggers[0]);
|
this.ruleForm.get("trigger").get("type").setValue(this.supportedTriggers[0]);
|
||||||
}
|
}
|
||||||
|
getLabelListFromAdapter(supportedFilter) {
|
||||||
|
if (supportedFilter.type === 'label') {
|
||||||
|
this.supportedFilterLabels = [];
|
||||||
|
supportedFilter.values.forEach( value => {
|
||||||
|
this.supportedFilterLabels.push({
|
||||||
|
name: value,
|
||||||
|
color: '#fff',
|
||||||
|
select: false,
|
||||||
|
scope: 'g'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getLabelListFromRuleInfo(ruleInfo) {
|
||||||
|
let labelValueObj = ruleInfo.filters.find((currentValue) => {
|
||||||
|
return currentValue.type === '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: '#fff',
|
||||||
|
select: true,
|
||||||
|
scope: 'g'
|
||||||
|
}, ...this.supportedFilterLabels];
|
||||||
|
}
|
||||||
|
//
|
||||||
|
for (const labelObj of this.supportedFilterLabels) {
|
||||||
|
if (labelObj.name === labelValue) {
|
||||||
|
labelObj.select = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
close(): void {
|
close(): void {
|
||||||
this.createEditRuleOpened = false;
|
this.createEditRuleOpened = false;
|
||||||
}
|
}
|
||||||
@ -482,4 +553,20 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
return trigger_settingsControls.controls.cron.touched || trigger_settingsControls.controls.cron.dirty;
|
return trigger_settingsControls.controls.cron.touched || trigger_settingsControls.controls.cron.dirty;
|
||||||
}
|
}
|
||||||
|
stickLabel(value, index) {
|
||||||
|
value.select = !value.select;
|
||||||
|
let filters = this.ruleForm.get('filters') as FormArray;
|
||||||
|
let fromIndex = filters.controls[index] as FormGroup;
|
||||||
|
let labelValue = this.supportedFilterLabels.reduce( (cumulatedSelectedArrs, currentValue) => {
|
||||||
|
if (currentValue.select) {
|
||||||
|
if (!cumulatedSelectedArrs.length) {
|
||||||
|
return [currentValue.name];
|
||||||
|
}
|
||||||
|
return [...cumulatedSelectedArrs, currentValue.name];
|
||||||
|
}
|
||||||
|
return cumulatedSelectedArrs;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
fromIndex.setControl('value', this.fb.array(labelValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ export interface ReplicationRule extends Base {
|
|||||||
|
|
||||||
export class Filter {
|
export class Filter {
|
||||||
type: string;
|
type: string;
|
||||||
value?: string;
|
value?: any;
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
"TOOLTIP": {
|
"TOOLTIP": {
|
||||||
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
||||||
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
||||||
|
"LABEL_FILTER": "Filter the resources according to labels.",
|
||||||
"RESOURCE_FILTER": "Filter the type of resources.",
|
"RESOURCE_FILTER": "Filter the type of resources.",
|
||||||
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
||||||
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
"TOOLTIP": {
|
"TOOLTIP": {
|
||||||
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
||||||
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
||||||
|
"LABEL_FILTER": "Filter the resources according to labels.",
|
||||||
"RESOURCE_FILTER": "Filter the type of resources.",
|
"RESOURCE_FILTER": "Filter the type of resources.",
|
||||||
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
||||||
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
"TOOLTIP": {
|
"TOOLTIP": {
|
||||||
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
||||||
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
||||||
|
"LABEL_FILTER": "Filter the resources according to labels.",
|
||||||
"RESOURCE_FILTER": "Filter the type of resources.",
|
"RESOURCE_FILTER": "Filter the type of resources.",
|
||||||
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
||||||
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
"TOOLTIP": {
|
"TOOLTIP": {
|
||||||
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
"NAME_FILTER": "Filter the name of the resource. Leave empty or use '**' to match all. 'library/**' only matches resources under 'library'. For more patterns, please refer to the user guide.",
|
||||||
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
"TAG_FILTER": "Filter the tag/version part of the resources. Leave empty or use '**' to match all. '1.0*' only matches the tags that starts with '1.0'. For more patterns, please refer to the user guide.",
|
||||||
|
"LABEL_FILTER": "Filter the resources according to labels.",
|
||||||
"RESOURCE_FILTER": "Filter the type of resources.",
|
"RESOURCE_FILTER": "Filter the type of resources.",
|
||||||
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
"PUSH_BASED": "Push the resources from the local Harbor to the remote registry.",
|
||||||
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
"PULL_BASED": "Pull the resources from the remote registry to the local Harbor.",
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
"TOOLTIP": {
|
"TOOLTIP": {
|
||||||
"NAME_FILTER": "过滤资源的名字。不填或者“”匹配所有资源;“library/”只匹配“library”下的资源。更多的匹配模式请参考用户手册。",
|
"NAME_FILTER": "过滤资源的名字。不填或者“”匹配所有资源;“library/”只匹配“library”下的资源。更多的匹配模式请参考用户手册。",
|
||||||
"TAG_FILTER": "过滤资源的tag/version。不填或者“”匹配所有;“1.0*”只匹配以“1.0”开头的tag/version。",
|
"TAG_FILTER": "过滤资源的tag/version。不填或者“”匹配所有;“1.0*”只匹配以“1.0”开头的tag/version。",
|
||||||
|
"LABEL_FILTER": "根据标签筛选资源。",
|
||||||
"RESOURCE_FILTER": "过滤资源的类型。",
|
"RESOURCE_FILTER": "过滤资源的类型。",
|
||||||
"PUSH_BASED": "把资源由本地Harbor推送到远端仓库。",
|
"PUSH_BASED": "把资源由本地Harbor推送到远端仓库。",
|
||||||
"PULL_BASED": "把资源由远端仓库拉取到本地Harbor。",
|
"PULL_BASED": "把资源由远端仓库拉取到本地Harbor。",
|
||||||
@ -86,8 +87,8 @@
|
|||||||
"NONEMPTY": "不能为空",
|
"NONEMPTY": "不能为空",
|
||||||
"ENDPOINT_FORMAT": "Endpoint必须以http://或https://开头。",
|
"ENDPOINT_FORMAT": "Endpoint必须以http://或https://开头。",
|
||||||
"OIDC_ENDPOIT_FORMAT": "Endpoint必须以https://开头。",
|
"OIDC_ENDPOIT_FORMAT": "Endpoint必须以https://开头。",
|
||||||
"OIDC_NAME": "OIDC提供商的名称.",
|
"OIDC_NAME": "OIDC提供商的名称。",
|
||||||
"OIDC_ENDPOINT": "OIDC服务器的地址.",
|
"OIDC_ENDPOINT": "OIDC服务器的地址。",
|
||||||
"OIDC_SCOPE": "在身份验证期间发送到OIDC服务器的scope。它必须包含“openid”和“offline_access”。如果您使用Google,请从此字段中删除“脱机访问”。",
|
"OIDC_SCOPE": "在身份验证期间发送到OIDC服务器的scope。它必须包含“openid”和“offline_access”。如果您使用Google,请从此字段中删除“脱机访问”。",
|
||||||
"OIDC_VERIFYCERT": "如果您的OIDC服务器是通过自签名证书托管的,请取消选中此框。"
|
"OIDC_VERIFYCERT": "如果您的OIDC服务器是通过自签名证书托管的,请取消选中此框。"
|
||||||
},
|
},
|
||||||
@ -298,7 +299,7 @@
|
|||||||
"NEW_ROBOT_ACCOUNT": "添加机器人账户",
|
"NEW_ROBOT_ACCOUNT": "添加机器人账户",
|
||||||
"ENABLED_STATE": "启用状态",
|
"ENABLED_STATE": "启用状态",
|
||||||
"EXPIRATION": "过期时间",
|
"EXPIRATION": "过期时间",
|
||||||
"NUMBER_REQUIRED":"此项为必填项且为不为0的整数.",
|
"NUMBER_REQUIRED":"此项为必填项且为不为0的整数。",
|
||||||
"TOKEN_EXPIRATION":"机器人账户令牌过期时间(天)",
|
"TOKEN_EXPIRATION":"机器人账户令牌过期时间(天)",
|
||||||
"DESCRIPTION": "描述",
|
"DESCRIPTION": "描述",
|
||||||
"ACTION": "操作",
|
"ACTION": "操作",
|
||||||
@ -314,10 +315,10 @@
|
|||||||
"PUSH": "推送",
|
"PUSH": "推送",
|
||||||
"PULL": "拉取",
|
"PULL": "拉取",
|
||||||
"FILTER_PLACEHOLDER": "过滤机器人账户",
|
"FILTER_PLACEHOLDER": "过滤机器人账户",
|
||||||
"ROBOT_NAME": "不能包含特殊字符(~#$%)且长度不能超过255.",
|
"ROBOT_NAME": "不能包含特殊字符(~#$%)且长度不能超过255。",
|
||||||
"ACCOUNT_EXISTING": "机器人账户已经存在.",
|
"ACCOUNT_EXISTING": "机器人账户已经存在。",
|
||||||
"ALERT_TEXT": "这是唯一一次复制您的个人访问令牌的机会",
|
"ALERT_TEXT": "这是唯一一次复制您的个人访问令牌的机会",
|
||||||
"CREATED_SUCCESS": "创建账户 '{{param}}' 成功.",
|
"CREATED_SUCCESS": "创建账户 '{{param}}' 成功。",
|
||||||
"COPY_SUCCESS": "成功复制 '{{param}}' 的令牌",
|
"COPY_SUCCESS": "成功复制 '{{param}}' 的令牌",
|
||||||
"DELETION_TITLE": "删除账户确认",
|
"DELETION_TITLE": "删除账户确认",
|
||||||
"DELETION_SUMMARY": "你确认删除机器人账户 {{param}}?"
|
"DELETION_SUMMARY": "你确认删除机器人账户 {{param}}?"
|
||||||
@ -727,7 +728,7 @@
|
|||||||
"TOKEN_EXPIRATION": "由令牌服务创建的令牌的过期时间(分钟),默认为30分钟。",
|
"TOKEN_EXPIRATION": "由令牌服务创建的令牌的过期时间(分钟),默认为30分钟。",
|
||||||
"ROBOT_TOKEN_EXPIRATION": "机器人账户的令牌的过期时间(天),默认为30天,显示的结果为分钟转化的天数并向下取整。",
|
"ROBOT_TOKEN_EXPIRATION": "机器人账户的令牌的过期时间(天),默认为30天,显示的结果为分钟转化的天数并向下取整。",
|
||||||
"PRO_CREATION_RESTRICTION": "用来确定哪些用户有权限创建项目,默认为’所有人‘,设置为’仅管理员‘则只有管理员可以创建项目。",
|
"PRO_CREATION_RESTRICTION": "用来确定哪些用户有权限创建项目,默认为’所有人‘,设置为’仅管理员‘则只有管理员可以创建项目。",
|
||||||
"ROOT_CERT_DOWNLOAD": "下载镜像库根证书.",
|
"ROOT_CERT_DOWNLOAD": "下载镜像库根证书。",
|
||||||
"SCANNING_POLICY": "基于不同需求设置镜像扫描策略。‘无’:不设置任何策略;‘每日定时’:每天在设置的时间定时执行扫描。",
|
"SCANNING_POLICY": "基于不同需求设置镜像扫描策略。‘无’:不设置任何策略;‘每日定时’:每天在设置的时间定时执行扫描。",
|
||||||
"VERIFY_CERT": "检查来自LDAP服务端的证书",
|
"VERIFY_CERT": "检查来自LDAP服务端的证书",
|
||||||
"READONLY_TOOLTIP": "选中,表示正在维护状态,不可删除仓库及标签,也不可以推送镜像。",
|
"READONLY_TOOLTIP": "选中,表示正在维护状态,不可删除仓库及标签,也不可以推送镜像。",
|
||||||
@ -859,8 +860,8 @@
|
|||||||
},
|
},
|
||||||
"CHART": {
|
"CHART": {
|
||||||
"SCANNING_TIME": "扫描完成时间:",
|
"SCANNING_TIME": "扫描完成时间:",
|
||||||
"TOOLTIPS_TITLE": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}.",
|
"TOOLTIPS_TITLE": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
||||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}.",
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
||||||
"TOOLTIPS_TITLE_ZERO": "没有发现可识别的漏洞包"
|
"TOOLTIPS_TITLE_ZERO": "没有发现可识别的漏洞包"
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
|
Loading…
Reference in New Issue
Block a user