mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-26 10:38:00 +01:00
Make label filter editable for replication rule (#18357)
1. Fixes #15825 2. Now, you can input labels or select them from the candidates Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
e76aff6a0a
commit
339f5b106b
@ -272,69 +272,25 @@
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="dropdown clr-select-wrapper"
|
||||
formArrayName="value">
|
||||
<clr-dropdown class="width-tag-label">
|
||||
<div
|
||||
class="width-100 label-text"
|
||||
clrDropdownTrigger>
|
||||
<div class="label-container">
|
||||
<ng-template
|
||||
ngFor
|
||||
let-label
|
||||
[ngForOf]="
|
||||
filter.value.value
|
||||
"
|
||||
let-m="index">
|
||||
<hbr-label-piece
|
||||
class="label-piece"
|
||||
*ngIf="m < 1 && label"
|
||||
[hasIcon]="false"
|
||||
[label]="
|
||||
getLabel(label)
|
||||
"
|
||||
[labelWidth]="
|
||||
84
|
||||
"></hbr-label-piece>
|
||||
</ng-template>
|
||||
<span
|
||||
class="ellipsis color-white-dark"
|
||||
*ngIf="
|
||||
filter.value.value
|
||||
.length > 1
|
||||
"
|
||||
>···</span
|
||||
>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
class="clr-input-wrapper position-relative width-tag-label">
|
||||
<input
|
||||
class="clr-input width-tag-label label-input"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
id="labelFilter"
|
||||
[(ngModel)]="stringForLabelFilter"
|
||||
[ngModelOptions]="{
|
||||
standalone: true
|
||||
}" />
|
||||
<clr-dropdown>
|
||||
<clr-icon
|
||||
class="down"
|
||||
clrDropdownTrigger
|
||||
shape="caret"
|
||||
dir="down">
|
||||
</clr-icon>
|
||||
<clr-dropdown-menu
|
||||
[ngStyle]="{ 'max-height.px': 230 }"
|
||||
class="right-align"
|
||||
@ -346,11 +302,13 @@
|
||||
*ngFor="
|
||||
let value of supportedFilterLabels
|
||||
"
|
||||
(click)="stickLabel(value, i)">
|
||||
(click)="
|
||||
stickLabel(value.name)
|
||||
">
|
||||
<clr-icon
|
||||
shape="check"
|
||||
[style.visibility]="
|
||||
value.select
|
||||
isSelect(value.name)
|
||||
? 'visible'
|
||||
: 'hidden'
|
||||
"></clr-icon>
|
||||
|
@ -272,7 +272,7 @@ clr-modal {
|
||||
.right-align {
|
||||
min-width: 204px;
|
||||
overflow-y: auto;
|
||||
transform: translateX(-4.3rem) translateY(1.25rem)!important;
|
||||
transform: translateX(-9rem) translateY(1.25rem)!important;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
@ -327,3 +327,19 @@ clr-modal {
|
||||
.bandwidth {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.down {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
right: 0.2rem;
|
||||
color: rgb(164 164 164) !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dropdown {
|
||||
left: -1.2rem;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.label-input {
|
||||
padding-right: 1.2rem;
|
||||
}
|
||||
|
@ -95,7 +95,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
supportedFilterLabels: {
|
||||
name: string;
|
||||
color: string;
|
||||
select: boolean;
|
||||
scope: string;
|
||||
}[] = [];
|
||||
|
||||
@ -118,6 +117,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
selectedUnit: string = BandwidthUnit.KB;
|
||||
copySpeedUnit: string = BandwidthUnit.KB;
|
||||
showChunkOption: boolean = false;
|
||||
stringForLabelFilter: string = '';
|
||||
copyStringForLabelFilter: string = '';
|
||||
constructor(
|
||||
private fb: UntypedFormBuilder,
|
||||
private repService: ReplicationService,
|
||||
@ -365,9 +366,23 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
this.isPushMode = true;
|
||||
this.selectedUnit = BandwidthUnit.KB;
|
||||
this.stringForLabelFilter = '';
|
||||
}
|
||||
|
||||
updateRuleFormAndCopyUpdateForm(rule: ReplicationPolicy): void {
|
||||
if (rule?.filters?.length) {
|
||||
// set stringForLabelFilter
|
||||
this.stringForLabelFilter = '';
|
||||
this.copyStringForLabelFilter = '';
|
||||
rule.filters.forEach(item => {
|
||||
if (item.type === FilterType.LABEL) {
|
||||
this.stringForLabelFilter = (item.value as string[]).join(
|
||||
','
|
||||
);
|
||||
this.copyStringForLabelFilter = this.stringForLabelFilter;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.isPushMode = rule.dest_registry.id !== 0;
|
||||
this.checkChunkOption(rule.dest_registry.id || rule.src_registry.id);
|
||||
setTimeout(() => {
|
||||
@ -482,6 +497,10 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
// speed unit has been changed
|
||||
return true;
|
||||
}
|
||||
if (this.copyStringForLabelFilter !== this.stringForLabelFilter) {
|
||||
// label filter has been changed
|
||||
return true;
|
||||
}
|
||||
return !isEmptyObject(this.hasChanges());
|
||||
}
|
||||
|
||||
@ -511,6 +530,18 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
copyRuleForm.dest_registry = null;
|
||||
}
|
||||
let filters: any = copyRuleForm.filters;
|
||||
|
||||
// set label filter
|
||||
if (this.stringForLabelFilter) {
|
||||
// set stringForLabelFilter
|
||||
copyRuleForm.filters.forEach(item => {
|
||||
if (item.type === FilterType.LABEL) {
|
||||
item.value = this.stringForLabelFilter
|
||||
.split(',')
|
||||
.filter(item => item);
|
||||
}
|
||||
});
|
||||
}
|
||||
// remove the filters which user not set.
|
||||
for (let i = filters.length - 1; i >= 0; i--) {
|
||||
if (
|
||||
@ -575,30 +606,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
this.noEndpointInfo = 'REPLICATION.NO_ENDPOINT_INFO';
|
||||
}
|
||||
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 as any).length
|
||||
) {
|
||||
(f.value as any).forEach(name => {
|
||||
if (label.name === name) {
|
||||
this.supportedFilterLabels[
|
||||
index
|
||||
].select = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
this.onGoing = true;
|
||||
this.policyId = +rule.id;
|
||||
this.headerTitle = 'REPLICATION.EDIT_POLICY_TITLE';
|
||||
@ -634,14 +641,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
adapter => {
|
||||
this.setFilterAndTrigger(adapter);
|
||||
this.copyUpdateForm = clone(this.ruleForm.value);
|
||||
if (
|
||||
this.supportedFilterLabels &&
|
||||
this.supportedFilterLabels.length
|
||||
) {
|
||||
this.supportedFilterLabels.forEach((label, index) => {
|
||||
label.select = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
(error: any) => {
|
||||
this.inlineAlert.showInlineError(error);
|
||||
@ -746,24 +745,20 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
stickLabel(value, index) {
|
||||
value.select = !value.select;
|
||||
let filters = this.ruleForm.get('filters') as UntypedFormArray;
|
||||
let fromIndex = filters.controls[index] as UntypedFormGroup;
|
||||
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));
|
||||
stickLabel(name: string) {
|
||||
if (this.isSelect(name)) {
|
||||
let arr: string[] = this.stringForLabelFilter.split(',');
|
||||
arr = arr.filter(item => {
|
||||
return item !== name;
|
||||
});
|
||||
this.stringForLabelFilter = arr.join(',');
|
||||
} else {
|
||||
if (this.stringForLabelFilter) {
|
||||
this.stringForLabelFilter += `,${name}`;
|
||||
} else {
|
||||
this.stringForLabelFilter += `${name}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
// set prefix '0 ', so user can not set item of 'seconds'
|
||||
inputInvalid(e: any) {
|
||||
@ -820,7 +815,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
this.supportedFilterLabels.push({
|
||||
name: data.name,
|
||||
color: data.color ? data.color : '#FFFFFF',
|
||||
select: false,
|
||||
scope: 'g',
|
||||
});
|
||||
});
|
||||
@ -849,7 +843,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
color: data.color
|
||||
? data.color
|
||||
: '#FFFFFF',
|
||||
select: false,
|
||||
scope: 'g',
|
||||
});
|
||||
});
|
||||
@ -880,17 +873,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
return realSpeed ? realSpeed : -1;
|
||||
}
|
||||
}
|
||||
getLabel(labelName: string): Label {
|
||||
if (this.supportedFilterLabels?.length) {
|
||||
let label: Label;
|
||||
this.supportedFilterLabels.forEach(item => {
|
||||
if (item.name === labelName) {
|
||||
label = item;
|
||||
}
|
||||
});
|
||||
return label;
|
||||
}
|
||||
}
|
||||
checkChunkOption(id: number, info?: RegistryInfo) {
|
||||
this.showChunkOption = false;
|
||||
this.ruleForm.get('copy_by_chunk').reset(false);
|
||||
@ -906,4 +888,11 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isSelect(v: string) {
|
||||
if (v && this.stringForLabelFilter) {
|
||||
return this.stringForLabelFilter.indexOf(v) !== -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user