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:
Shijun Sun 2023-03-17 15:48:03 +08:00 committed by GitHub
parent e76aff6a0a
commit 339f5b106b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 129 deletions

View File

@ -272,69 +272,25 @@
</option> </option>
</select> </select>
</div> </div>
<div <div
class="dropdown clr-select-wrapper" class="clr-input-wrapper position-relative width-tag-label">
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 <input
class="clr-input width-tag-label label-input"
autocomplete="off"
type="text" type="text"
[formControlName]="k" id="labelFilter"
#labelValue [(ngModel)]="stringForLabelFilter"
id="{{ [ngModelOptions]="{
'label_' + standalone: true
supportedFilters[i] }" />
?.type + <clr-dropdown>
'_' + <clr-icon
label1 class="down"
}}" clrDropdownTrigger
name="{{ shape="caret"
'label_' + dir="down">
supportedFilters[i] </clr-icon>
?.type +
'_' +
label1
}}"
placeholder="select labels" />
</div>
</div>
<clr-dropdown-menu <clr-dropdown-menu
[ngStyle]="{ 'max-height.px': 230 }" [ngStyle]="{ 'max-height.px': 230 }"
class="right-align" class="right-align"
@ -346,11 +302,13 @@
*ngFor=" *ngFor="
let value of supportedFilterLabels let value of supportedFilterLabels
" "
(click)="stickLabel(value, i)"> (click)="
stickLabel(value.name)
">
<clr-icon <clr-icon
shape="check" shape="check"
[style.visibility]=" [style.visibility]="
value.select isSelect(value.name)
? 'visible' ? 'visible'
: 'hidden' : 'hidden'
"></clr-icon> "></clr-icon>

View File

@ -272,7 +272,7 @@ clr-modal {
.right-align { .right-align {
min-width: 204px; min-width: 204px;
overflow-y: auto; overflow-y: auto;
transform: translateX(-4.3rem) translateY(1.25rem)!important; transform: translateX(-9rem) translateY(1.25rem)!important;
} }
.dropdown-item { .dropdown-item {
@ -327,3 +327,19 @@ clr-modal {
.bandwidth { .bandwidth {
margin-top: 0.25rem; 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;
}

View File

@ -95,7 +95,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
supportedFilterLabels: { supportedFilterLabels: {
name: string; name: string;
color: string; color: string;
select: boolean;
scope: string; scope: string;
}[] = []; }[] = [];
@ -118,6 +117,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
selectedUnit: string = BandwidthUnit.KB; selectedUnit: string = BandwidthUnit.KB;
copySpeedUnit: string = BandwidthUnit.KB; copySpeedUnit: string = BandwidthUnit.KB;
showChunkOption: boolean = false; showChunkOption: boolean = false;
stringForLabelFilter: string = '';
copyStringForLabelFilter: string = '';
constructor( constructor(
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private repService: ReplicationService, private repService: ReplicationService,
@ -365,9 +366,23 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
}); });
this.isPushMode = true; this.isPushMode = true;
this.selectedUnit = BandwidthUnit.KB; this.selectedUnit = BandwidthUnit.KB;
this.stringForLabelFilter = '';
} }
updateRuleFormAndCopyUpdateForm(rule: ReplicationPolicy): void { 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.isPushMode = rule.dest_registry.id !== 0;
this.checkChunkOption(rule.dest_registry.id || rule.src_registry.id); this.checkChunkOption(rule.dest_registry.id || rule.src_registry.id);
setTimeout(() => { setTimeout(() => {
@ -482,6 +497,10 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
// speed unit has been changed // speed unit has been changed
return true; return true;
} }
if (this.copyStringForLabelFilter !== this.stringForLabelFilter) {
// label filter has been changed
return true;
}
return !isEmptyObject(this.hasChanges()); return !isEmptyObject(this.hasChanges());
} }
@ -511,6 +530,18 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
copyRuleForm.dest_registry = null; copyRuleForm.dest_registry = null;
} }
let filters: any = copyRuleForm.filters; 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. // 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 ( if (
@ -575,30 +606,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
this.noEndpointInfo = 'REPLICATION.NO_ENDPOINT_INFO'; this.noEndpointInfo = 'REPLICATION.NO_ENDPOINT_INFO';
} }
if (rule) { 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.onGoing = true;
this.policyId = +rule.id; this.policyId = +rule.id;
this.headerTitle = 'REPLICATION.EDIT_POLICY_TITLE'; this.headerTitle = 'REPLICATION.EDIT_POLICY_TITLE';
@ -634,14 +641,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
adapter => { adapter => {
this.setFilterAndTrigger(adapter); this.setFilterAndTrigger(adapter);
this.copyUpdateForm = clone(this.ruleForm.value); this.copyUpdateForm = clone(this.ruleForm.value);
if (
this.supportedFilterLabels &&
this.supportedFilterLabels.length
) {
this.supportedFilterLabels.forEach((label, index) => {
label.select = false;
});
}
}, },
(error: any) => { (error: any) => {
this.inlineAlert.showInlineError(error); this.inlineAlert.showInlineError(error);
@ -746,24 +745,20 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
} }
return false; return false;
} }
stickLabel(value, index) { stickLabel(name: string) {
value.select = !value.select; if (this.isSelect(name)) {
let filters = this.ruleForm.get('filters') as UntypedFormArray; let arr: string[] = this.stringForLabelFilter.split(',');
let fromIndex = filters.controls[index] as UntypedFormGroup; arr = arr.filter(item => {
let labelValue = this.supportedFilterLabels.reduce( return item !== name;
(cumulatedSelectedArrs, currentValue) => { });
if (currentValue.select) { this.stringForLabelFilter = arr.join(',');
if (!cumulatedSelectedArrs.length) { } else {
return [currentValue.name]; if (this.stringForLabelFilter) {
this.stringForLabelFilter += `,${name}`;
} else {
this.stringForLabelFilter += `${name}`;
} }
return [...cumulatedSelectedArrs, currentValue.name];
} }
return cumulatedSelectedArrs;
},
[]
);
fromIndex.setControl('value', this.fb.array(labelValue));
} }
// set prefix '0 ', so user can not set item of 'seconds' // set prefix '0 ', so user can not set item of 'seconds'
inputInvalid(e: any) { inputInvalid(e: any) {
@ -820,7 +815,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
this.supportedFilterLabels.push({ this.supportedFilterLabels.push({
name: data.name, name: data.name,
color: data.color ? data.color : '#FFFFFF', color: data.color ? data.color : '#FFFFFF',
select: false,
scope: 'g', scope: 'g',
}); });
}); });
@ -849,7 +843,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
color: data.color color: data.color
? data.color ? data.color
: '#FFFFFF', : '#FFFFFF',
select: false,
scope: 'g', scope: 'g',
}); });
}); });
@ -880,17 +873,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
return realSpeed ? realSpeed : -1; 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) { checkChunkOption(id: number, info?: RegistryInfo) {
this.showChunkOption = false; this.showChunkOption = false;
this.ruleForm.get('copy_by_chunk').reset(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;
}
} }